Skip to content
GraphQL Schema Federation: Composing a Unified Graph from Multiple Services 4 min

GraphQL Schema Federation: Composing a Unified Graph from Multiple Services

SD
ScaleDojo
May 11, 2026
4 min read886 words
Schema Federation: Composing a Unified Graph from Multiple Services

Netflix's 2000-Type Schema Problem

Netflix's GraphQL schema grew past 2,000 types. Hundreds of engineers across dozens of teams all had to coordinate changes to one massive schema file, and the pain showed up everywhere: constant merge conflicts, and deploys that meant shipping everyone's code together whether they were ready or not. The fix was GraphQL Schema Federation, which lets each team own its slice of the graph independently while clients still see one unified API.

This is the same tension you run into with any large-scale system design problem: how do you give teams autonomy without turning the client-facing contract into chaos. Federation is GraphQL's answer to that question.

How Federation Works

Without Federation (Monolithic Schema):

  [Team A]  [Team B]  [Team C]
      \\       |       /
       v      v      v
  [One Giant Schema File]  <-- merge conflicts, coordinated deploys
         |
    [GraphQL Server]
         |
    [All Clients]

With Federation (Distributed Subgraphs):

  [Team A]     [Team B]      [Team C]
     |            |              |
  [Users       [Orders        [Reviews
   Subgraph]    Subgraph]      Subgraph]
     |            |              |
     +------[Gateway/Router]-----+
           (Apollo Router)
              |
         [All Clients]
         See ONE unified schema

The gateway (or router, in Apollo's terminology) is the piece doing all the work here. It's conceptually close to an API gateway or BFF layer, except instead of just routing and aggregating REST calls, it's stitching together a single GraphQL schema and planning queries across it.

Subgraph Schema Example

# Users Subgraph (owned by Team A):
type User @key(fields: 'id') {
  id: ID!
  name: String!
  email: String!
  avatar: String
}

# Orders Subgraph (owned by Team B):
type Order {
  id: ID!
  total: Float!
  items: [OrderItem!]!
}

# Extends User from Team A's subgraph:
extend type User @key(fields: 'id') {
  id: ID! @external
  orders: [Order!]!    # Team B ADDS this field to User
}

# Reviews Subgraph (owned by Team C):
extend type User @key(fields: 'id') {
  id: ID! @external
  reviews: [Review!]!  # Team C ADDS this field to User
}

# Client sees ONE unified User type:
# User { id, name, email, avatar, orders, reviews }
# Client has NO IDEA these come from 3 different services

Notice what's happening with the @key directive: each subgraph declares how its entity is identified, and other subgraphs can extend that entity without owning it. Team B never touches Team A's code, it just adds an orders field to User from its own subgraph. That's the core trick behind GraphQL Schema Federation, and it's what makes GraphQL Microservices actually workable at org scale instead of just theoretically nice.

Query Execution Across Subgraphs

Client sends:
  query {
    user(id: 42) {
      name           # from Users subgraph
      orders {       # from Orders subgraph
        total
      }
      reviews {      # from Reviews subgraph
        rating
      }
    }
  }

Gateway creates a query plan:
  1. Fetch User(id:42) from Users subgraph -> {name}
  2. In parallel:
     a. Fetch orders for User(id:42) from Orders subgraph
     b. Fetch reviews for User(id:42) from Reviews subgraph
  3. Merge results and return to client

Latency = max(Users, max(Orders, Reviews))
not sum(Users + Orders + Reviews)

That parallel fan-out is the whole point. A naive implementation would hit each subgraph sequentially and pay for it in latency. A proper Apollo Federation setup builds a query plan up front and fires off independent branches concurrently, which is the same principle you'd apply when fanning out calls to independent services or queues, similar to how event-driven systems described in AMQP, Kafka, and Event Sourcing avoid blocking on one slow consumer.

Federation vs Schema Stitching vs BFF

Approach          Team Ownership  Gateway Smarts   Deployment
----------------  --------------  ---------------  -----------------
Monolithic GQL    Shared (pain)   None             All together
Schema Stitching  Moderate        Gateway merges   Coordinated
Federation v2     Full ownership  Query planning   Independent
BFF (REST)        Per client      None (per app)   Independent

Federation wins when: 5+ teams, 50+ types, independent deploys

Schema stitching was federation's predecessor, and it required a central gateway team to manually merge schemas together, which just moves the coordination bottleneck rather than removing it. BFF (Backend for Frontend) solves a different problem: it's per-client aggregation, usually over REST, and it doesn't give you a single graph at all. If you're weighing these tradeoffs for your own architecture, the API Gateway, BFF, and multi-protocol architecture post covers where each pattern fits. Federated GraphQL Architecture is really the option you reach for once you have enough teams and enough types that a shared schema file becomes a liability rather than a convenience.

Interview Tip

When discussing GraphQL at scale, say: 'For a large engineering org, I would use Apollo Federation v2. Each team owns a subgraph with their types and resolvers, deploying independently. A gateway router composes subgraphs into one unified schema using @key directives to link entities across boundaries. The router creates optimized query plans that fetch from subgraphs in parallel. This gives teams autonomy while clients see a seamless, unified API.'

Schema Federation: Composing a Unified Graph from Multiple Services - Architecture Diagram

Architecture overview

Key Takeaway

Schema federation splits a GraphQL schema across multiple services (subgraphs), each owned by a different team. A gateway composes them into one unified API. This enables independent development and deployment while presenting a seamless API to clients.

If you're studying this pattern for system design interviews or just trying to fill gaps in your architecture knowledge, it's worth pairing with related topics like caching at the gateway layer (see Caching Strategies) and event-driven contracts between services (see AsyncAPI, CloudEvents, and the Transactional Outbox Pattern). Federation solves the schema-ownership problem, but the services behind it still need solid caching and messaging decisions to hold up under real traffic.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo