GraphQL Union Types

A union type groups together multiple object types under one name without requiring them to share any fields. When a field returns a union, the response can be any one of the listed types. Unions are perfect for search results and feeds that mix different kinds of content.

Interface vs Union — The Key Difference

  Interface                        Union
  ─────────                        ─────
  Member types share fields        Member types share nothing
  Query common fields directly     Must use inline fragments
  Good for related entities        Good for unrelated entities
  (Car, Truck both have speed)     (Book, Movie, User in search)

Defining a Union

  type BlogPost {
    title:   String!
    content: String!
  }

  type ImagePost {
    caption: String!
    imageUrl:String!
  }

  type VideoPost {
    title:    String!
    videoUrl: String!
    duration: Int!
  }

  union FeedItem = BlogPost | ImagePost | VideoPost
               ↑
              pipe symbol separates the member types

Querying a Union

Because union members share no guaranteed fields, every field selection must appear inside an inline fragment. There is no common field you can query outside a fragment.

  Schema:
  ────────
  type Query {
    feed: [FeedItem!]!
  }

  Query:
  ───────
  {
    feed {
      __typename           ← Always works, tells you the type
      ... on BlogPost {
        title
        content
      }
      ... on ImagePost {
        caption
        imageUrl
      }
      ... on VideoPost {
        title
        duration
      }
    }
  }

  Response:
  ──────────
  {
    "feed": [
      {
        "__typename": "BlogPost",
        "title": "GraphQL in 2025",
        "content": "GraphQL continues to grow..."
      },
      {
        "__typename": "ImagePost",
        "caption": "Team lunch",
        "imageUrl": "https://cdn.example.com/lunch.jpg"
      },
      {
        "__typename": "VideoPost",
        "title": "GraphQL Tutorial",
        "duration": 1800
      }
    ]
  }

Search Result Union Pattern

The most common use of unions is a search API that returns different types of results. A user searches for "Apollo" and gets back companies, people, and space missions all in one list.

  type Company  { name: String! industry: String! }
  type Person   { name: String! title: String!    }
  type Product  { name: String! price: Float!      }

  union SearchResult = Company | Person | Product

  type Query {
    search(term: String!): [SearchResult!]!
  }

  Query:
  ───────
  {
    search(term: "Apollo") {
      __typename
      ... on Company { name industry }
      ... on Person  { name title    }
      ... on Product { name price    }
    }
  }

Handling Unknown Types in the Client

Client code should always handle unknown types gracefully. When the schema adds a new union member in the future, old client code that does not have a fragment for the new type simply receives nothing for those objects. The app does not crash.

  {
    feed {
      __typename
      ... on BlogPost  { title }
      ... on ImagePost { caption }
      /* No fragment for VideoPost — VideoPost objects
         appear in response with only __typename.
         Client ignores them silently. */
    }
  }

Key Points

  • A union groups multiple types under one name without requiring shared fields.
  • Every field in a union query must live inside an inline fragment (... on TypeName).
  • The __typename field identifies which type each result is at runtime.
  • Unions are ideal for mixed-content feeds and multi-type search results.
  • Adding new types to a union does not break existing clients — they simply ignore the unknown type.

Leave a Comment