GraphQL Schema Stitching

Schema stitching combines multiple separate GraphQL schemas into one unified schema. Clients query a single endpoint and receive data that may come from several different services, each with its own schema. The stitching layer merges them transparently.

The Problem Schema Stitching Solves

  Without stitching — clients talk to many servers:
  ──────────────────────────────────────────────────
  Client ──► Users Service  (localhost:4001/graphql)
  Client ──► Orders Service (localhost:4002/graphql)
  Client ──► Products Service (localhost:4003/graphql)
  (Client manages 3 connections)

  With stitching — one gateway for everything:
  ─────────────────────────────────────────────
  Client ──► Gateway (localhost:4000/graphql)
               │
               ├──► Users Service   (internal)
               ├──► Orders Service  (internal)
               └──► Products Service (internal)
  (Client sees one endpoint, one schema)

Basic Schema Stitching with @graphql-tools

  npm install @graphql-tools/stitch @graphql-tools/wrap graphql

  import { stitchSchemas } from '@graphql-tools/stitch';
  import { buildSchema } from 'graphql';

  // Schema A — Users
  const usersSchema = buildSchema(`
    type User {
      id:   ID!
      name: String!
    }
    type Query {
      user(id: ID!): User
    }
  `);

  // Schema B — Orders
  const ordersSchema = buildSchema(`
    type Order {
      id:     ID!
      total:  Float!
      userId: ID!
    }
    type Query {
      order(id: ID!): Order
      ordersByUser(userId: ID!): [Order]
    }
  `);

  // Stitch them together
  const gatewaySchema = stitchSchemas({
    subschemas: [
      { schema: usersSchema },
      { schema: ordersSchema },
    ]
  });

Linking Types Across Schemas

The real power of stitching comes from linking types across schemas. You extend the User type from the users schema to include orders from the orders schema. The gateway resolves the link automatically.

  Type merging — User gets an orders field:
  ──────────────────────────────────────────
  const gatewaySchema = stitchSchemas({
    subschemas: [
      { schema: usersSchema },
      { schema: ordersSchema },
    ],
    typeDefs: `
      extend type User {
        orders: [Order]
      }
    `,
    resolvers: {
      User: {
        orders: {
          selectionSet: '{ id }',
          resolve: (user, _args, _context, info) => {
            return delegateToSchema({
              schema:    ordersSchema,
              operation: 'query',
              fieldName: 'ordersByUser',
              args:      { userId: user.id },
              info,
            });
          }
        }
      }
    }
  });

  Client can now query across both services:
  ────────────────────────────────────────────
  {
    user(id: "u5") {
      name          ← from Users Service
      orders {      ← from Orders Service, linked by userId
        id
        total
      }
    }
  }

Schema Stitching vs Federation

  Schema Stitching              Federation (Apollo)
  ────────────────              ───────────────────
  Managed centrally             Each service owns its type
  Gateway does the merging      Services annotate with @key
  Services need no changes      Services use federation spec
  More control at gateway       Better for large org teams
  Easier to start               Better for scale

When to Use Schema Stitching

Use schema stitching when you have existing GraphQL services that you cannot modify, when you want to merge third-party GraphQL APIs, or when you need a lightweight gateway without adopting the full Apollo Federation specification.

Key Points

  • Schema stitching merges multiple GraphQL schemas into one unified schema at a gateway.
  • Clients see one endpoint and one schema regardless of how many services sit behind it.
  • Type merging extends types from one schema with fields resolved by another service.
  • Stitching works well for combining existing services; Federation is better for large distributed teams.

Leave a Comment