iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

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…