Federation
GraphQL Federation: compose multiple subgraphs into a single supergraph. Apollo Federation 2, entities, and the patterns for microservices.
GraphQL — federation
EXAMPLE
// ===== The problem =====
// Microservices: each owns its data + types.
// Clients want ONE GraphQL endpoint, not 10.
// Solution: a SUPERGRAPH that combines SUBGRAPHS.
// ===== Apollo Federation 2 =====
// Each subgraph is a regular GraphQL service with federation directives.
// The Apollo Router (or Gateway) composes them into a supergraph.
// ===== Users subgraph =====
// users-service/schema.graphql
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"])
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
type Query {
user(id: ID!): User
}
# Resolver:
const resolvers = {
Query: {
user: (_, { id }) => db.users.findById(id),
},
User: {
__resolveReference: (ref) => db.users.findById(ref.id),
},
};
// ===== Orders subgraph =====
// orders-service/schema.graphql
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@external"])
type Order @key(fields: "id") {
id: ID!
total: Int!
user: User! # references the User type from users-service
}
type User @key(fields: "id") {
id: ID! @external
orders: [Order!]!
}
type Query {
order(id: ID!): Order
}
# Resolver:
const resolvers = {
Query: {
order: (_, { id }) => db.orders.findById(id),
},
Order: {
user: (order) => ({ __typename: 'User', id: order.user_id }),
__resolveReference: (ref) => db.orders.findById(ref.id),
},
User: {
orders: (user) => db.orders.findByUserId(user.id),
},
};
// Users-service resolves User by id; orders-service ADDS the .orders field to User.
// ===== Composition =====
// rover (Apollo CLI):
rover supergraph compose --config supergraph.yaml > supergraph.graphql
// supergraph.yaml:
subgraphs:
users: { routing_url: 'http://users:4001/graphql', schema: { subgraph_url: 'http://users:4001/graphql' } }
orders: { routing_url: 'http://orders:4002/graphql', schema: { subgraph_url: 'http://orders:4002/graphql' } }
// Apollo Router serves the supergraph.
// ===== Client experience =====
// Clients query a single endpoint; the router fans out:
query {
user(id: "u-1") {
name
orders { id total }
}
}
// ===== Patterns =====
// - One service per business domain owns one part of the graph
// - @key fields define how entities are identified across services
// - DataLoader within each subgraph for N+1
// - Schema registry (Apollo Studio / GraphOS) for version validation
// ===== When to use =====
// - Many backend services with overlapping types (User, Order)
// - Need a unified GraphQL surface for many clients
// - Large teams wanting independent deploys
// ===== When NOT to use =====
// - Single service / small team
// - Simple monolith with stable schema
// - High-throughput public API where router overhead matters
// ===== Pitfalls =====
// - Schema drift between subgraphs without checks
// - Circular type dependencies
// - Auth model not aligned across subgraphs
// - Performance: every cross-service field is an extra query
Why it matters
Federation composes microservice graphs into one supergraph: @key entities, @external references, Apollo Router. Each team owns their slice; clients see one endpoint. Worth the complexity at scale; overkill for single-service apps.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
# Stitch independent subgraphs into one supergraph. # Apollo Federation / GraphQL Mesh / Hasura Cloud all do this.Try it Yourself »
Discussion
Loading…