Learn GraphQL - Building Distributed Schemas with Federation
Episode 22 of 51

Learn GraphQL - Building Distributed Schemas with Federation

Episode 22 builds distributed schemas with Apollo Federation 2: the supergraph and gateway concepts, the @key, @shareable, @override, and @interfaceObject directives, how to build subgraphs, setting up Apollo Gateway with composition and query planning, and migration strategies from a monolith.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

As teams and domains grow, a single giant schema becomes a bottleneck: every change requires coordination from everyone. Episode 22 introduces Apollo Federation — an architecture that splits the schema into subgraphs owned by each team, then combines them into a single supergraph.

We'll learn the supergraph and gateway concepts, the key Federation 2 directives, how to build subgraphs, setting up Apollo Gateway with query planning, and a step-by-step migration strategy from a monolith.

Federation Concepts

Monolith vs Federated GraphQL

In federated GraphQL, each domain (user, product, order) becomes a subgraph — a standalone GraphQL service with its own partial schema. All subgraphs are combined by a gateway into a supergraph, which clients see as a single endpoint.

Supergraph architecture
client -> gateway -> subgraph users
                  -> subgraph products
                  -> subgraph orders

The benefits: each team owns its own schema, deploys independently, and scales per domain. The challenge: composing schemas across services needs clear rules — that's where the federation directives come in.

Apollo Federation 2

Key Directives

Federation 2 (the latest stable version) simplifies composition with directives:

  • @key(fields: "id"): marks a unique field as the cross-subgraph entity reference.
  • @shareable: a field that may be defined by multiple subgraphs.
  • @override(from: "OtherSubgraph"): takes over a field's implementation from another subgraph.
  • @interfaceObject: lets a subgraph contribute fields to an interface.
Products subgraph with @key
type Product @key(fields: "upc") {
  upc: String!
  name: String!
  price: Int!
}
 
type Query {
  products: [Product!]!
}

Entity References and Extends

Another subgraph can extend the Product entity without owning its data:

The reviews subgraph extends Product
type Product @key(fields: "upc") {
  upc: String! @external
  reviews: [Review!]! @requires(fields: "upc")
}
 
type Review {
  id: ID!
  body: String!
  rating: Int!
}

This pattern is the power of federation: the reviews service only knows upc, and the gateway gathers the complete data when a query needs both.

Building Subgraphs

Building a Subgraph with Apollo

Each subgraph is a regular Apollo server, built with buildSubgraphSchema:

Install subgraph dependencies
npm install @apollo/subgraph
JSSubgraph server
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { buildSubgraphSchema } from "@apollo/subgraph";
 
const schema = buildSubgraphSchema({ typeDefs, resolvers });
 
const server = new ApolloServer({ schema });
const { url } = await startStandaloneServer(server, { listen: { port: 4002 } });
console.log("Subgraph products di", url);

A subgraph is exposed to the gateway via its URL, along with its introspected schema. Every subgraph needs a __resolveReference resolver for entities that other subgraphs can reference:

JSThe __resolveReference resolver
const resolvers = {
  Product: {
    __resolveReference(ref, ctx) {
      return ctx.db.products.findByUpc(ref.upc);
    },
  },
  Query: {
    products: (_, __, ctx) => ctx.db.products.findAll(),
  },
};

Apollo Gateway

Gateway Setup and Query Planning

The gateway combines subgraphs. First install it via npm install @apollo/gateway @apollo/server, then define the subgraph list:

JSGateway with two subgraphs
import { ApolloGateway } from "@apollo/gateway";
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
 
const gateway = new ApolloGateway({
  supergraphSdl: `
    schema @link(url: "https://specs.apollo.dev/federation/v2.3") {
      query: Query
    }
    extend schema
      @link(url: "https://specs.apollo.dev/federation/v2.3",
            import: ["@key", "@shareable"])
  `,
  subgraphs: {
    users: { url: "http://localhost:4001" },
    products: { url: "http://localhost:4002" },
  },
});
 
const server = new ApolloServer({ gateway });
const { url } = await startStandaloneServer(server, { listen: { port: 4000 } });

The gateway does two important things: composition (combining subgraphs into a supergraph) and query planning (splitting one client query into calls to the right subgraphs). Clients only deal with the gateway — the supergraph endpoint.

Federation Patterns and Migration

Common Patterns and Monitoring

A frequently used pattern: value types (simple objects without their own identity, which can be @shareable) versus entities (which have a @key). For monitoring, the gateway and each subgraph can send tracing to Apollo Studio, making the query journey across services visible.

Migrating a Monolith to Federation

A gradual migration so clients aren't disrupted:

  1. Split one domain into a subgraph, still loaded inside the monolith first.
  2. Once stable, move the subgraph to a separate service.
  3. Repeat per domain; the gateway abstracts the changes from clients.

This incremental approach is used by many companies — and we'll dissect it again in the microservices context in episode 36.

Conclusion

Key takeaways:

  • Federation splits the schema into subgraphs owned by each team.
  • @key marks entity references; @external and @requires enable cross-subgraph extensions.
  • @shareable and @override govern field ownership in Federation 2.
  • Each subgraph is built with buildSubgraphSchema and __resolveReference.
  • The gateway combines subgraphs via composition and splits queries via query planning.
  • Migrating a monolith to federation is done gradually, domain by domain.

In the next episode, episode 23, you'll learn about GraphQL Code Generator and type safety — installing and configuring codegen, generating TypeScript types from the schema, generating typed React hooks, type-safe resolvers and context, and integrating watch mode and pre-commit hooks. You'll experience end-to-end type safety!

Learn GraphQL - Building Distributed Schemas with Federation | Learn GraphQL