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
__typenamefield 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.
