Skip to content

Interfaces and Unions

So far every field has had exactly one object type. But real domains have polymorphism: a search result might be a user or a post; a notification might be a mention, a like, or a follow. GraphQL has two abstract types for this — interfaces and unions — and a way to select the right fields per concrete type using inline fragments. This lesson covers all three and, crucially, when to use which.

Section titled “Interfaces — shared fields across related types”

An interface declares a set of fields that several object types all promise to provide. Any type that implements the interface must include those fields. Use an interface when several types are genuinely variations of one concept and share data:

interface Media {
id: ID!
title: String!
durationSeconds: Int!
}
type Episode implements Media {
id: ID!
title: String!
durationSeconds: Int!
seasonNumber: Int!
}
type Movie implements Media {
id: ID!
title: String!
durationSeconds: Int!
rating: String
}

Both Episode and Movie are Media: they share id, title, and durationSeconds, but each adds its own fields. A field can now return the interface — media: [Media!]! — and the value will be one of the implementing types at runtime.

A union says a value is exactly one of a listed set of object types, with no required shared fields. Use a union when the alternatives do not naturally share data — they just happen to appear in the same slot:

union SearchResult = Episode | Movie | Person
type Person {
id: ID!
name: String!
}
type Query {
search(term: String!): [SearchResult!]!
}

A SearchResult is an Episode, a Movie, or a Person. There is no field every search result must have — a Person has nothing in common with a Movie beyond turning up in the same list. That is the signal for a union rather than an interface.

flowchart TD
  Interface["interface Media (shared: id, title, durationSeconds)"]
  Episode["type Episode"]
  Movie["type Movie"]
  Interface --> Episode
  Interface --> Movie
  Union["union SearchResult (no shared fields)"]
  Person["type Person"]
  Union --> Episode
  Union --> Movie
  Union --> Person
An interface shares fields among related types; a union lists unrelated alternatives.

When a field can return more than one concrete type, the client needs a way to ask “which one is this, and give me its specific fields.” GraphQL provides the built-in __typename field — it returns the concrete type’s name as a string — and inline fragments to select fields conditionally per type:

{
search(term: "graph") {
__typename
... on Episode {
title
seasonNumber
}
... on Movie {
title
rating
}
... on Person {
name
}
}
}

Read ... on Movie as “if this result is a Movie, also select these fields.” For an interface you can select the shared fields directly (no fragment needed) and use inline fragments only for the type-specific extras. __typename is almost always worth requesting on a polymorphic field — clients use it to decide which branch of their own code to run.

The example below defines a Media union of Episode and Movie, returns a mixed list, and uses __typename plus inline fragments to pull the right fields from each. Press Run.

JavaScript

Each item in the list came back tagged with its __typename, and only the inline fragment matching that type contributed fields. The Episode carried seasonNumber; the Movie carried rating. One field, two shapes, fully type-safe.

What is the defining difference between an interface and a union?
What does the built-in __typename field return?
How do you select fields that exist only on one specific type of a union?
Which scenario best fits a union rather than an interface?