GraphQL Interfaces

An interface defines a set of fields that multiple types must include. Any type that implements an interface guarantees those fields exist. Interfaces let you write queries that work across different types that share common fields.

The Problem Interfaces Solve

A content platform has Articles, Videos, and Podcasts. All three share a title, author, and publish date. Without an interface, you write three separate queries for three different types. With an interface, you write one query that works for all content types through the shared fields.

  Without interface:           With interface:
  ──────────────────           ───────────────
  Article  { title, author }   interface Content {
  Video    { title, author }     title:  String!
  Podcast  { title, author }     author: String!
                                 publishedAt: String!
  3 separate queries needed    }

                               Article implements Content
                               Video   implements Content
                               Podcast implements Content

                               1 query using Content fields

Defining an Interface

  interface Vehicle {
    id:           ID!
    manufacturer: String!
    topSpeed:     Int!
  }

  type Car implements Vehicle {
    id:           ID!       ← Required by interface
    manufacturer: String!   ← Required by interface
    topSpeed:     Int!      ← Required by interface
    doors:        Int!      ← Extra field, Car-specific
  }

  type Motorcycle implements Vehicle {
    id:           ID!       ← Required by interface
    manufacturer: String!   ← Required by interface
    topSpeed:     Int!      ← Required by interface
    sidecar:      Boolean   ← Extra field, Motorcycle-specific
  }

Querying Through an Interface

A query can target the interface type. Common fields are available directly. Type-specific fields require an inline fragment with ... on TypeName.

  Schema:
  ────────
  type Query {
    vehicles: [Vehicle]   ← Returns a mix of Car and Motorcycle
  }

  Query:
  ───────
  {
    vehicles {
      manufacturer       ← Works for ALL Vehicle types
      topSpeed           ← Works for ALL Vehicle types
      ... on Car {
        doors            ← Only for Car objects
      }
      ... on Motorcycle {
        sidecar          ← Only for Motorcycle objects
      }
    }
  }

  Response:
  ──────────
  {
    "vehicles": [
      {
        "manufacturer": "Honda",
        "topSpeed": 220,
        "doors": 4          ← Car fields included
      },
      {
        "manufacturer": "Royal Enfield",
        "topSpeed": 160,
        "sidecar": false    ← Motorcycle fields included
      }
    ]
  }

The __typename Meta Field

The __typename field tells you which concrete type an object is at runtime. This is useful when your client needs to know whether it received a Car or a Motorcycle to render the right component.

  {
    vehicles {
      __typename       ← Ask what type this is
      manufacturer
      ... on Car {
        doors
      }
    }
  }

  Response:
  ──────────
  {
    "vehicles": [
      { "__typename": "Car",        "manufacturer": "Honda",       "doors": 4 },
      { "__typename": "Motorcycle", "manufacturer": "Royal Enfield" }
    ]
  }

One Type Can Implement Multiple Interfaces

  interface Identifiable { id: ID! }
  interface Timestamped  { createdAt: String! }

  type Post implements Identifiable & Timestamped {
    id:        ID!
    createdAt: String!
    title:     String!
  }

Key Points

  • An interface defines required fields that implementing types must include.
  • Multiple types can implement the same interface, sharing a common query surface.
  • Query interface fields directly; use ... on TypeName inline fragments for type-specific fields.
  • The __typename meta field identifies the concrete type of an object at runtime.
  • A type can implement multiple interfaces by listing them with &.

Leave a Comment