Skip to content
API Design Learn/GraphQL at Scale
Browsing as a guest. Sign in to save your progress and earn XP as you complete chapters.

Schema Federation

8 min read

You'll learn to

  • -Explain what problem schema federation solves for organizations with multiple teams owning different parts of one logical graph
  • -Use the core federation directives (@key, @external, @requires) to compose a type across service boundaries

A single GraphQL schema works well for a single team or a single service. Once an organization has multiple teams, each owning a different domain (users, orders, inventory) but wanting one unified graph for clients to query, a monolithic schema becomes a coordination bottleneck - every team's changes touch the same shared schema file, and no team can deploy independently.

The Problem Federation Solves

Apollo Federation (the dominant approach in practice) lets each team own and deploy its own subgraph independently, while a gateway composes all the subgraphs into one unified graph that clients query as if it were a single schema. A client's query might touch types owned by three different teams' services in one request, with the gateway routing and stitching the results together transparently.

The @key Directive: Identifying a Shared Entity

The Users subgraph owns the core User type
# --- users subgraph ---
type User @key(fields: "id") {
  id: ID!
  name: String!
  email: String!
}
The Orders subgraph extends User with its own fields, without owning the type
# --- orders subgraph ---
type User @key(fields: "id") {
  id: ID!
  orders: [Order!]!   # this subgraph adds a NEW field to a type it doesn't own
}

type Order {
  id: ID!
  total: Float!
}

`@key(fields: "id")` declares that `id` is how this type is uniquely identified across subgraphs - both the Users and Orders subgraphs reference the same logical `User` entity by that shared key, and the gateway uses it to know which subgraph to call for which fields, then merges the results into one `User` object in the response.

@external and @requires: Depending on Another Subgraph's Data

Computing a field that needs data owned by a different subgraph
# --- orders subgraph ---
type User @key(fields: "id") {
  id: ID!
  email: String! @external          # not owned here, but referenced
  orderNotificationEmail: String! @requires(fields: "email")
}

`@external` marks a field this subgraph references but does not own the source of truth for (email genuinely belongs to the Users subgraph). `@requires(fields: "email")` says "to compute `orderNotificationEmail`, I need the `email` field's value first" - the gateway resolves the dependency by fetching `email` from the Users subgraph before calling the Orders subgraph's resolver for `orderNotificationEmail`, so cross-subgraph data dependencies are declared explicitly rather than each subgraph having to fetch the other's data itself.

Federation is a tool for organizational scaling (independent team ownership and deployment), not primarily a performance optimization - a single well-designed monolithic schema, for a team small enough to coordinate easily, is usually simpler to reason about and should remain the default until team boundaries genuinely demand independent ownership.

Interview Signal is part of Pro

See a real weak answer next to a real strong one for this exact topic.

Quiz is part of Pro

Test what you just read with a short quiz, and bank the XP.

Ready to Build This?

Design Schema Federation in the API Design Lab's GraphQL Mastery act.

ScaleDojo Logo
Initializing ScaleDojo