Federation and Schema Stitching

Advanced
14 min

Federation and Schema Stitching

One schema is the whole point for clients, but one server owned by one team does not scale to an organisation. Federation and stitching let several services publish parts of one graph behind one endpoint. After this lesson you will be able to write a federated subgraph with entities, compose subgraphs behind a router, and know when stitching is enough.

One Graph, Many Services

| Approach | Where the graph is combined | Who declares relationships | Best for | |---|---|---|---| | Apollo Federation | A router serving a composed supergraph | Each subgraph, via @key | Many teams owning domains | | Schema stitching | A gateway using @graphql-tools/stitch | The gateway, by merging types | Existing or third-party APIs |

Each service still runs an ordinary GraphQL server; the difference is where knowledge of how types connect lives.

Writing a Federated Subgraph

Federation revolves around entities, types that several subgraphs contribute fields to. A subgraph declares one with @key and provides __resolveReference so the router can fetch it by key:

javascript
import { ApolloServer } from "@apollo/server"; import { buildSubgraphSchema } from "@apollo/subgraph"; import gql from "graphql-tag"; const typeDefs = gql` extend schema @link(url: "https://specs.apollo.dev/federation/v2.9", import: ["@key"]) type User @key(fields: "id") { id: ID! name: String! } type Query { user(id: ID!): User } `; const resolvers = { Query: { user: (_p, { id }, { db }) => db.users.find(id) }, User: { __resolveReference: (ref, { db }) => db.users.find(ref.id) }, }; const server = new ApolloServer({ schema: buildSubgraphSchema({ typeDefs, resolvers }) });

A second subgraph can add fields to User without owning its data; it needs only the key:

javascript
const typeDefs = gql` # same @link header as above type Review @key(fields: "id") { id: ID! body: String! author: User! } type User @key(fields: "id") { id: ID! reviews: [Review!]! } `; const resolvers = { Review: { author: (review) => ({ __typename: "User", id: review.authorId }) }, User: { reviews: (user, _a, { db }) => db.reviews.byAuthor(user.id) }, };

Returning { __typename: "User", id } is enough: the router knows name lives in the users subgraph and calls its __resolveReference. A query for { user(id: "1") { name reviews { body } } } is planned across both services.

Composing and Serving the Supergraph

Subgraphs are composed into a supergraph schema that a router executes. In development, @apollo/gateway composes at startup by introspecting the subgraphs:

javascript
import { ApolloGateway, IntrospectAndCompose } from "@apollo/gateway"; const gateway = new ApolloGateway({ supergraphSdl: new IntrospectAndCompose({ subgraphs: [ { name: "users", url: "http://localhost:4001/" }, { name: "reviews", url: "http://localhost:4002/" }, ], }), });

For production, compose ahead of time with rover supergraph compose --config supergraph.yaml > supergraph.graphql and run Apollo Router, a Rust binary with query planning, caching and telemetry. Composition fails when subgraphs conflict, turning integration problems into build errors.

Schema Stitching

Stitching combines complete schemas in a gateway. Each remote schema gets an executor, and the gateway merges types with the same name:

javascript
import { stitchSchemas } from "@graphql-tools/stitch"; import { buildHTTPExecutor } from "@graphql-tools/executor-http"; import { schemaFromExecutor } from "@graphql-tools/wrap"; const usersExec = buildHTTPExecutor({ endpoint: "http://localhost:4001/graphql" }); const reviewsExec = buildHTTPExecutor({ endpoint: "http://localhost:4002/graphql" }); const schema = stitchSchemas({ subschemas: [ { schema: await schemaFromExecutor(usersExec), executor: usersExec }, { schema: await schemaFromExecutor(reviewsExec), executor: reviewsExec }, ], });

A merge configuration per subschema plays the role of @key. Stitching needs no changes to the underlying services.

Tips

  • Start with a modular monolith; split only when teams need independent deployment.
  • Keep entity keys stable and minimal (id), and run composition checks in CI.
Quick Quiz
Question 1 of 2

What is the purpose of `__resolveReference` in a subgraph?

Key Takeaways

  • Federation keeps relationship knowledge in subgraphs; stitching keeps it in the gateway.
  • A subgraph declares entities with @key and implements __resolveReference; others extend them via stubs.
  • Subgraphs compose into a supergraph served by Apollo Router or @apollo/gateway.
  • @graphql-tools/stitch merges complete remote schemas, ideal for legacy APIs.
  • Split a schema only when team boundaries demand it.

Next lesson: GraphQL Best Practices and When to Use It — consolidate naming, nullability and evolution rules, and weigh GraphQL against REST.

Federation and Schema Stitching - GraphQL | CodeYourCraft | CodeYourCraft