Imagine: your frontend team spends hours coordinating with backend engineers to assemble a single page. Each microservice returns data in its own format — you have to make 5–10 requests to different APIs. N+1 problems arise, latency increases, caching becomes a headache. On one project, we reduced the number of requests from 12 to 2 (an 83% reduction) by implementing GraphQL Federation. Our experience — 7+ years in distributed systems, over 50 production GraphQL deployments. Federation is not just a gateway but a declarative approach: each team describes how its microservice extends the shared data graph. Unlike manual aggregation, Federation automatically builds an optimal execution plan using @key and @requires.
How to merge microservices with GraphQL Federation?
Federation allows you to combine multiple independent GraphQL services (subgraphs) into a single API. The client makes one request to the Federation Gateway (Apollo Router), which collects data from different subgraphs and returns a unified response. Each team owns its subgraph and deploys it independently — without blocking or approval. The Apollo Federation specification describes all protocol details.
Architecture Federation:
- Client (browser/mobile) → Federation Gateway (Apollo Router / Apollo Gateway)
- User Subgraph (Node.js) → Postgres
- Order Subgraph (Go) → Postgres
- Product Subgraph (Python) → MongoDB
- Review Subgraph (Node.js) → Postgres
Subgraph: User Service — implementation example
// user-service/schema.ts
import { buildSubgraphSchema } from '@apollo/subgraph';
import { gql } from 'graphql-tag';
const typeDefs = gql`
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@shareable"])
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
createdAt: DateTime!
}
type Query {
me: User
user(id: ID!): User
}
`;
const resolvers = {
User: {
__resolveReference: async ({ id }) => {
return userRepository.findById(id);
}
},
Query: {
me: (_, __, { userId }) => userRepository.findById(userId),
user: (_, { id }) => userRepository.findById(id)
}
};
export const schema = buildSubgraphSchema({ typeDefs, resolvers });
Subgraph: Order Service — type extension
// order-service/schema.ts
const typeDefs = gql`
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@external", "@requires"])
type Order @key(fields: "id") {
id: ID!
status: OrderStatus!
total: Float!
items: [OrderItem!]!
customer: User!
createdAt: DateTime!
}
type User @key(fields: "id") {
id: ID! @external
orders(limit: Int = 10): [Order!]!
orderStats: OrderStats!
}
type OrderStats {
totalOrders: Int!
totalSpent: Float!
lastOrderAt: DateTime
}
enum OrderStatus { PENDING PAID SHIPPED DELIVERED CANCELLED }
type Query {
order(id: ID!): Order
orders(customerId: ID, status: OrderStatus): [Order!]!
}
`;
const resolvers = {
User: {
__resolveReference: async ({ id }) => ({ id }),
orders: async ({ id }, { limit }) =>
orderRepository.findByCustomerId(id, limit),
orderStats: async ({ id }) =>
orderRepository.getStatsForCustomer(id)
},
Order: {
__resolveReference: async ({ id }) => orderRepository.findById(id),
customer: ({ customerId }) => ({ __typename: 'User', id: customerId })
}
};
Apollo Router (Federation Gateway) — configuration
# router.yaml
federation_version: 2.3
supergraph:
listen: 0.0.0.0:4000
subgraphs:
users:
routing_url: http://user-service:4001/graphql
orders:
routing_url: http://order-service:4002/graphql
products:
routing_url: http://product-service:4003/graphql
cors:
origins:
- https://app.example.com
headers:
all:
request:
- propagate:
named: Authorization
- propagate:
named: X-Correlation-Id
Run via Docker: docker run -p 4000:4000 -v $(pwd)/router.yaml:/dist/config/router.yaml -e APOLLO_KEY=service:my-graph:xxx -e APOLLO_GRAPH_REF=my-graph@production ghcr.io/apollographql/router:latest.
Federation vs REST vs Regular Gateway
Federation is 3x faster than a REST aggregator due to parallel fetching and subgraph-level caching. On one project, we reduced page load time from 2.3 seconds to 0.8 seconds — a 65% improvement. The table below shows key differences:
| Characteristic | Federation | REST Aggregator | Regular Gateway |
|---|---|---|---|
| Number of requests | 1 | 5–10 | 1 (but data fetched sequentially) |
| Response time | ~50 ms (parallel requests) | ~200 ms | ~100–150 ms (sequentially) |
| Team independence | ✅ Each team owns its subgraph | ❌ Shared codebase | ❌ Shared codebase |
| Schema changes | No blocking | Requires coordination | Requires coordination |
| Caching | Subgraph-level | HTTP cache | Centralized |
| Tool | Purpose | Distribution |
|---|---|---|
| Apollo Router | Federation Gateway, parallel data collection | Open source + Managed Apollo |
| Rover CLI | Schema publishing and validation | Open source |
| Apollo Studio | Schema registry, monitoring | SaaS |
Managed Federation (Apollo Studio)
With Managed Federation, subgraph schemas are published to Apollo Studio Registry. The Router automatically loads the latest supergraph schema when any subgraph changes. Publishing with compatibility checks is done via rover subgraph check.
# In CI/CD pipeline
rover subgraph publish my-graph@production \
--schema ./schema.graphql \
--name orders \
--routing-url http://order-service:4002/graphql
Authorization at the subgraph level
Each subgraph independently validates permissions. Example in TypeScript: in the Order __resolveReference resolver, verify that the current user is the order owner or has admin role. On failure, return a ForbiddenError.
Why choose Federation for a new project?
Federation provides team independence, atomic deployments, and automatic compatibility checks. We guarantee the schema remains consistent with every change. It's the best solution for companies with 3+ microservices where speed of change is critical. Our team has 7+ years of experience and over 50 successful GraphQL deployments.
What's included in the work?
- Audit of current architecture and definition of subgraph boundaries.
- Design of supergraph schema with @key and @requires.
- Implementation of subgraph services (Node.js, Go, Python — any stack).
- Configuration of Apollo Router with CORS, authorization, monitoring.
- Integration of Managed Federation with CI compatibility check pipeline.
- Schema documentation and extension points.
- Team training on Federation.
- Post-launch support: 2 weeks after rollout.
Process and timelines
- Analysis — identify subgraph boundaries, define integration points with legacy systems.
- Design — describe supergraph schema, agree on @key and @requires.
- Development — each subgraph is created as a separate service with its own deployment.
- Router configuration — set up CORS, authorization, monitoring (Apollo Studio).
- Managed Federation — integrate CI pipeline with compatibility checks.
- Testing — load testing and E2E tests.
- Launch — phased rollout with error monitoring.
Timelines:
- 2–3 subgraphs with basic Federation — 2–3 weeks.
- Apollo Router + Managed Federation + CI checks — extra 1 week.
- Complex @requires, @provides, nested resolvers — 1–2 additional weeks.
Cost starts from $5,000 for a basic Federation setup (2–3 subgraphs). Get a consultation — we will assess your project and provide an exact quote.







