smaple.tr
GraphQL federation

GraphQL Federation Guide: Apollo Federation v2, Subgraph Design, and Supergraph Architecture [2026]

Mehmet Kurtipek
July 4, 2026
10 min read
GraphQL federation
Apollo Federation
subgraph
supergraph
microservices GraphQL

Microservice architectures solve the scaling problem — independent teams can deploy independently, services can scale independently, and a failure in one service does not bring down the rest. But they introduce a new problem at the API layer: clients that need data from three different services must either make three separate API calls or wait for a backend-for-frontend layer to aggregate them. GraphQL federation solves this.

GraphQL federation composes multiple independent GraphQL services (subgraphs) into a single unified API (supergraph) that clients interact with as if it were one service. Each team owns and deploys their subgraph independently. The gateway routes queries to the appropriate subgraphs, fetches the data in parallel where possible, and assembles the result. From the client's perspective: one endpoint, one query, one response.

This guide covers the full GraphQL federation architecture: subgraph design, entity resolution, Apollo Federation v2 features, gateway and router options, performance optimization, and the migration strategy from REST or monolithic GraphQL. By the end, you will have a clear picture of when federation is the right architectural choice and how to implement it correctly.

GraphQL Federation vs. Monolithic GraphQL

Before committing to federation, the tradeoff is worth stating directly:

Dimension Monolithic GraphQL Federated GraphQL
Team autonomy Low — schema changes require coordination High — each team owns their subgraph
Deployment All schema changes deploy together Subgraphs deploy independently
Schema management One schema file Distributed subgraph schemas
Performance overhead Low — single service Moderate — gateway + network hops between subgraphs
Operational complexity Low High — gateway, schema composition, distributed tracing
Breaking change scope One service One subgraph, isolated from others

Federation is the right choice when:

  • Multiple teams work on independent domains and coupling their deployments creates friction
  • Different parts of the API need to scale independently
  • You want to migrate incrementally from a monolith to microservices without breaking API consumers

A single-team application with a monolithic backend should use a monolithic GraphQL API. The operational overhead of federation — maintaining a gateway, managing subgraph discovery, debugging distributed query plans — is only justified when team autonomy and independent deployment are real requirements.

Subgraph Design: Domain Boundaries

Subgraph boundaries should follow domain boundaries, not technical convenience. The goal is to align each subgraph with a bounded context — a cohesive set of types and operations owned by one team with one deployment lifecycle.

For an e-commerce platform:

  • Users subgraph: account management, profiles, addresses, authentication state
  • Products subgraph: product catalog, categories, inventory counts, pricing
  • Orders subgraph: order creation, order status, fulfillment
  • Reviews subgraph: product reviews, ratings, moderation

Each subgraph defines the types and resolvers for its domain. The gateway composes them into a supergraph that lets clients query across domains in a single request.

The wrong way to split subgraphs: by database table (one subgraph per table) or by team size (splitting a single domain across two subgraphs because two teams work on it). These produce fragmented schemas that leak implementation details into the API design.

Entities: The Federation Building Block

The fundamental mechanism of GraphQL federation is the entity: a type defined in one subgraph that other subgraphs can extend or reference.

An entity is any type decorated with the @key directive, which specifies the field(s) used to identify and look up the entity:

# Users subgraph — defines the User entity
type User @key(fields: "id") {
  id: ID!
  email: String!
  displayName: String!
  createdAt: DateTime!
}

Other subgraphs can extend this entity to add domain-specific fields:

# Orders subgraph — extends User with order history
extend type User @key(fields: "id") {
  id: ID! @external
  orders(first: Int, after: String): OrderConnection!
  totalSpent: Float!
}

The @external directive on id tells the Orders subgraph: "I don't own this field; the Users subgraph does. But I need it to look up the related orders."

When the gateway receives a query that spans both subgraphs — requesting a user's email (from Users) and their orders (from Orders) — it:

  1. Fetches the user's id, email, and displayName from the Users subgraph
  2. Sends the id to the Orders subgraph to fetch orders and totalSpent
  3. Merges the results into a single response

The Orders subgraph must implement a __resolveReference resolver that accepts a reference (an object containing the @key fields) and returns the full entity:

const resolvers = {
  User: {
    __resolveReference: async ({ id }, { db }) => {
      // Batch-load with DataLoader for N+1 prevention
      return userOrderDataLoader.load(id);
    }
  }
};

Apollo Federation v2 Features

Apollo Federation v2 introduced several features that make federation more flexible than v1:

@shareable: allows a field to be defined in multiple subgraphs. In v1, each field could only be resolved by one subgraph. In v2, fields marked @shareable can be resolved by any subgraph that defines them — useful for shared utility types like address or pagination structures.

# Both Users and Shipping subgraphs can resolve this type
type Address @shareable {
  street: String!
  city: String!
  postalCode: String!
  country: String!
}

@override: transfers ownership of a field from one subgraph to another. Used during migrations: mark a field with @override(from: "OldSubgraph") in the new subgraph to gradually move it during a rolling deployment.

@inaccessible: hides a field from the public supergraph schema while keeping it resolvable internally. Useful for internal coordination fields that should not be exposed to external clients.

@requires: declares that a subgraph's resolver needs additional fields from the entity's owning subgraph to compute a value:

# Products subgraph computes a discounted price
extend type User @key(fields: "id") {
  id: ID! @external
  subscriptionTier: String! @external
  personalizedPrice(productId: ID!): Float! @requires(fields: "subscriptionTier")
}

The @requires directive tells the gateway to fetch subscriptionTier from the Users subgraph before calling the Products subgraph resolver for personalizedPrice.

Schema Composition and the Supergraph

Schema composition converts multiple subgraph schemas into a single supergraph schema. In Apollo Federation, the rover CLI performs composition:

rover supergraph compose --config supergraph.yaml > supergraph.graphql

The supergraph.yaml configuration file lists each subgraph with its routing URL and schema location:

federation_version: =2.7
subgraphs:
  users:
    routing_url: http://users-service:4001/graphql
    schema:
      file: ./schemas/users.graphql
  products:
    routing_url: http://products-service:4002/graphql
    schema:
      file: ./schemas/products.graphql

Composition fails with detailed error messages when subgraph schemas are incompatible — for example, when two subgraphs define @key entities with conflicting field types, or when @external fields don't match their definition in the owning subgraph.

CI/CD integration: run rover supergraph compose and schema validation in your CI pipeline on every subgraph deployment. A composition failure should block deployment. This is far cheaper than discovering an incompatibility in production.

Apollo Studio's schema registry provides managed schema composition with a history of all schema changes, composition validation, and breaking change detection. For teams operating multiple subgraphs, managed composition is worth the operational investment.

Gateway and Router Options

The gateway sits between clients and subgraphs, executing the query planning and subgraph dispatch.

Apollo Router is the recommended production option. Written in Rust for performance, it implements Federation v2 fully and is configuration-driven:

# router.yaml
supergraph:
  listen: 0.0.0.0:4000
  path: /graphql

headers:
  all:
    request:
      - propagate:
          named: "authorization"

traffic_shaping:
  all:
    timeout: 30s
  subgraphs:
    products:
      timeout: 10s

telemetry:
  exporters:
    tracing:
      otlp:
        enabled: true
        endpoint: http://jaeger:4317

Apollo Router supports ratefields-level caching, header propagation, OpenTelemetry tracing, and plugin-based extensibility. For most production deployments with Federation v2, Apollo Router is the correct choice.

Apollo Gateway (Node.js) is the predecessor. It is more flexible for custom JavaScript logic but slower than Apollo Router. Use it when you need custom plugin behavior that Apollo Router's configuration model doesn't support.

GraphQL Mesh can compose REST APIs, gRPC services, and GraphQL APIs into a unified GraphQL schema. It is valuable when migrating legacy REST APIs into a federation: wrap existing REST endpoints with Mesh, expose them as a subgraph, and migrate to native GraphQL resolvers incrementally.

Query Planning and Performance

The gateway's query planner analyzes each incoming query and creates a query plan: a tree of fetch operations against subgraphs, with parallelism where possible.

A query requesting fields from independent subgraphs (Users fields and Products fields) fetches them in parallel:

Parallel:
  Fetch Users subgraph (id, email)
  Fetch Products subgraph (product catalog)
Merge results → send to client

A query with entity traversal requires sequential fetches:

Fetch Users subgraph → get user id
Fetch Orders subgraph with user id → get order ids
Fetch Products subgraph with product ids → get product details
Merge results → send to client

Minimize sequential entity traversal by designing schemas to minimize cross-subgraph dependency chains. Deep nesting (User → Orders → OrderItems → Products) produces sequential query plans that multiply latency.

DataLoader in each subgraph is non-negotiable. Without it, entity resolution (__resolveReference calls) executes one database query per entity instance — the same N+1 problem that exists in monolithic GraphQL, amplified by the gateway's batching of multiple entity lookups.

Authentication and Authorization in Federation

Authentication happens at the gateway layer: the gateway validates JWTs or API keys and propagates the authenticated user identity to all subgraphs via request headers.

Authorization happens in subgraphs: each subgraph enforces authorization rules for the fields it owns. Apollo Federation v2 provides @authenticated and @requiresScopes directives for declarative authorization:

# Products subgraph
type Product @key(fields: "id") {
  id: ID!
  title: String!
  price: Float!
  costPrice: Float! @requiresScopes(scopes: [["admin"], ["finance"]])
  supplierNotes: String @requiresScopes(scopes: [["admin"]])
}

type Mutation {
  createProduct(input: ProductInput!): Product! @authenticated
  deleteProduct(id: ID!): Boolean! @requiresScopes(scopes: [["admin"]])
}

This approach keeps authentication centralized (one place to update) and authorization co-located with the data it protects (in the owning subgraph).

Migrating from REST or Monolithic GraphQL to Federation

For REST APIs: use GraphQL Mesh to wrap REST endpoints as a subgraph. Clients can query the GraphQL interface immediately while you migrate resolvers from REST calls to direct database access incrementally.

For monolithic GraphQL: extract subgraphs one domain at a time. Start with the domain with the fewest cross-domain entity relationships (typically the user management domain). Move it to a new subgraph, configure the gateway to route its types there, and validate that all existing queries still work. Each extraction is independently deployable and reversible.

The extraction process:

  1. Identify domain boundary — which types and resolvers belong together
  2. Create the new subgraph service with its own database access
  3. Define @key directives for entity types
  4. Configure __resolveReference resolvers
  5. Add to supergraph config and compose
  6. Validate with canary traffic before full migration
  7. Remove the types from the monolith after validation

The key risk in migration is entity resolution correctness — ensuring that cross-subgraph queries return the same results as the monolith. Contract tests and canary deployments with traffic comparison are the appropriate validation approach.

When to Choose Federation

Federation is justified when team autonomy and independent deployment are genuine requirements — when coupling deployments across teams creates meaningful friction. For a five-engineer startup building a single product, federation's operational overhead exceeds its benefits. For a 50-engineer organization with four product teams each owning different API domains, federation's benefits (independent deployment, schema isolation, subgraph-level scaling) are worth the investment.

If you are uncertain, start with a monolithic GraphQL API and migrate to federation when team structure and deployment frequency make the tradeoffs clear. A well-structured monolith can be extracted into subgraphs incrementally without breaking clients — the transition does not require a rewrite.

Related Articles

August 11, 2026

MLOps Guide: Taking Machine Learning Models to Production [2026]

87% of machine learning models built by data science teams never reach production. The models work — they pass cross-validation, they score well on holdout sets, they demonstrate genuine predictive value. The problem is not the modeling. The problem is everything that happens between a notebook experiment and a reliable, monitored, production system. MLOps is the discipline that closes that gap. This guide covers the full MLOps stack: maturity levels, tooling choices (MLflow, DVC, Kubeflow

Read More: MLOps Guide: Taking Machine Learning Models to Production [2026]
August 10, 2026

LLM Fine-Tuning Guide: Custom Model Training with LoRA and QLoRA [2026]

General-purpose LLMs are impressive. They can write code, summarize documents, answer questions, and translate between languages with reasonable accuracy. But "reasonable" is not good enough when your application requires consistent output format, domain-specific terminology, a particular tone, or behavior that the base model was never trained to exhibit. That gap is where fine-tuning matters. Fine-tuning updates a model's weights on your specific data, changing how the model behaves — not

Read More: LLM Fine-Tuning Guide: Custom Model Training with LoRA and QLoRA [2026]
August 9, 2026

Computer Vision Applications: Object Detection, OCR, and Industrial AI [2026]

Computer vision has moved well past the research phase. The models are trained, the frameworks are mature, the hardware is accessible, and the use cases are generating measurable returns. What was a specialized capability requiring deep expertise in 2018 is now deployable infrastructure — if you know which component to reach for and where the real complexity lives. This guide covers computer vision applications across industrial, medical, logistics, and document processing domains. It expl

Read More: Computer Vision Applications: Object Detection, OCR, and Industrial AI [2026]