🚀 Understanding GraphQL Federation in Microservices Architecture

Search for a command to run...

No comments yet. Be the first to comment.
GraphQL has gained tremendous popularity in recent years for its flexibility and efficiency in handling data. In this guide, we will walk you through the basics of GraphQL, the advantages it offers, and the steps to set up a Node.js project using Gra...
You implemented a search algorithm in your RAG system and it's returning data without any error, and you think that's it, you're done. You're wrong. That mindset works fine for a normal system — an AP

Every agentic AI system that "looks things up" before answering — a support bot searching a knowledge base, a coding agent searching a codebase, a research assistant searching PDFs — is running a Retr

RAG search has four moving parts: split the document, turn text into vectors, store those vectors somewhere queryable, and pull the right ones back out at query time. This post covers the last two — c

RAG systems live or die on one decision that happens before any embedding is computed: how the source document gets cut into pieces. This post walks through three chunking mechanisms available in Lang

This is Part 2 of an ongoing series on building a production-ready PostgreSQL AI agent using LangChain and Ollama. If you haven't read Part 1, start there — it covers the foundation: connecting to Pos

As applications grow in complexity, microservices become the go-to architectural pattern. But with them comes a new challenge: API sprawl. Each service manages its own schema, leading to a tangled mess of REST endpoints or isolated GraphQL APIs.
Enter GraphQL Federation—a powerful solution that lets you compose a unified GraphQL API from multiple microservices, while keeping each service independently developed and deployed.
In this article, we’ll break down what GraphQL Federation is, how it works, and why it’s a game-changer for modern backend systems.
GraphQL Federation is a technique introduced by Apollo that allows multiple GraphQL services (called subgraphs) to be merged into a single, unified API gateway (called the federated gateway).
It solves a critical issue in microservice architectures: how to let teams work independently on their own GraphQL schemas, while still offering a seamless client experience through a single graph.

| Component | Description |
| Subgraph | An individual GraphQL service with part of the overall schema |
| Federated Gateway | The GraphQL server that stitches all subgraphs into one unified schema |
| @key Directive | Used to define the primary key for an entity shared across subgraphs |
| @requires / @provides | Manage dependency fields between subgraphs |
If multiple services work on the same entity (e.g., User), the @key directive tells the gateway how to resolve it:
type User @key(fields: "id") {
id: ID!
name: String
}
A service can add fields to an entity defined in another service:
# In the reviews subgraph
extend type User @key(fields: "id") {
id: ID!
reviews: [Review]
}
The gateway uses service definitions from each subgraph (via introspection or static configs) and composes them into a single schema that the client can query.
Let’s say you're building an e-commerce platform with the following services:
User Service: Manages user data.
Product Service: Manages products available in the store.
Order Service: Manages customer orders and ties users to the products they purchase.
With GraphQL Federation, each service defines its part of the schema and can extend entities from other services to build a unified graph.
type User @key(fields: "id") {
id: ID!
name: String
email: String
}
This defines the User entity and its primary key (id). It can be referenced by other services.
type Product @key(fields: "id") {
id: ID!
name: String
price: Float
}
Each product has its own ID, name, and price.
type Order @key(fields: "id") {
id: ID!
quantity: Int
orderDate: String
user:User @provides(fields: "id")
product:Product @provides(fields: "id")
total: Float
}
extend type User @key(fields: "id") {
id: ID!
}
extend type Product @key(fields: "id") {
id: ID!
}
This service defines the Order entity, and extends both User and Product entities to show which users placed orders and which products were purchased.
Once the services are federated into a single gateway, clients can query them as one unified schema:
query {
orders {
id
quantity
orderDate
user {
id
name
email
}
product {
id
name
price
}
}
}
This single query fetches user details, their orders, and associated product details—even though the data is spread across three separate services.
The User Service owns the User type.
The Product Service owns the Product type.
The Order Service stitches everything together by referencing User and Product entities using the @extends directive.
This setup allows each team to focus on their domain, deploy independently, and still contribute to a shared graph that feels seamless to the client.
To federate your services using Apollo Federation, follow these steps:
Each service is an independent GraphQL server using the @apollo/subgraph package.
npm install @apollo/subgraph graphql
user-schema.graphql)type User @key(fields: "id") {
id: ID!
name: String
email: String
}
index.js)const { ApolloServer } = require('@apollo/server');
const { buildSubgraphSchema } = require('@apollo/subgraph');
const { startStandaloneServer } = require('@apollo/server/standalone');
const gql = require('graphql-tag');
const typeDefs = gql(require('fs').readFileSync('./user-schema.graphql', 'utf-8'));
const resolvers = {
User: {
__resolveReference(user) {
return users.find(u => u.id === user.id);
},
},
};
const server = new ApolloServer({
schema: buildSubgraphSchema([{ typeDefs, resolvers }]),
});
startStandaloneServer(server, { listen: { port: 4001 } });
product-schema.graphql)type Product @key(fields: "id") {
id: ID!
name: String
price: Float
}
index.js)Use the same @apollo/subgraph setup, listening on port 4002.
This one extends both User and Product entities.
order-schema.graphql)type Order @key(fields: "id") {
id: ID!
user: User
products: [Product]
total: Float
}
extend type User @key(fields: "id") {
id: ID!
orders: [Order]
}
extend type Product @key(fields: "id") {
id: ID!
purchasedBy: [User]
}
Use the same @apollo/subgraph setup, listening on port 4003.
This service composes the subgraphs and exposes one unified schema.
npm install @apollo/gateway graphql @apollo/server
gateway.js)const { ApolloServer } = require('@apollo/server');
const { ApolloGateway } = require('@apollo/gateway');
const { startStandaloneServer } = require('@apollo/server/standalone');
const gateway = new ApolloGateway({
serviceList: [
{ name: 'user', url: 'http://localhost:4001' },
{ name: 'product', url: 'http://localhost:4002' },
{ name: 'order', url: 'http://localhost:4003' },
],
});
const server = new ApolloServer({ gateway, subscriptions: false });
startStandaloneServer(server, { listen: { port: 4000 } }).then(({ url }) => {
console.log(`🚀 Gateway ready at ${url}`);
});
In separate terminal tabs or scripts:
# Terminal 1
node user/index.js
# Terminal 2
node product/index.js
# Terminal 3
node order/index.js
# Terminal 4
node gateway.js
Now your GraphQL API is live at http://localhost:4000/graphql and unified!
Test it with a powerful, nested query:
query {
orders {
id
quantity
orderDate
user {
id
name
email
}
product {
id
name
price
}
}
}
Even though user, order, and product are handled by separate microservices, this single query works flawlessly via federation!
Before adopting GraphQL Federation in your architecture, it’s important to weigh its advantages and potential challenges. Here’s a balanced look:
| Benefit | Description |
| Modular Architecture | Each subgraph service is owned and maintained by individual teams. This promotes autonomy and scalability. |
| Single Unified Graph | The client interacts with one clean, unified API—regardless of how many services are involved behind the scenes. |
| Independent Deployment | Subgraphs can be deployed independently without needing to rebuild or restart the gateway or other services. |
| Schema Collaboration | Teams can contribute to shared entities (e.g., User, Product) using directives like @extends and @key, enabling tight yet controlled coupling. |
| Optimized Developer Experience | Great tools from Apollo like Rover, schema registry, and schema checks make collaboration and CI/CD smooth. |
| Frontend Simplicity | Frontend developers can query complex relationships in a single request, improving developer productivity and reducing over-fetching. |
| Limitation | Description |
| Increased Operational Complexity | Managing multiple subgraph services and the gateway adds overhead to DevOps and deployment pipelines. |
| Cross-Team Coordination | Schema design requires coordination across teams when extending shared entities, especially in larger orgs. |
| Performance Bottlenecks | Poorly designed federated queries can result in N+1 problems or excessive network calls between services. Caching and batching become more critical. |
| Learning Curve | Developers must understand GraphQL directives (@key, @extends, etc.), entity resolution, and subgraph architecture. |
| Debugging Can Be Tricky | When things break, it can be harder to trace errors across subgraphs and the gateway. |
| Gateway is a Single Point of Failure | Unless properly scaled and load-balanced, the Apollo Gateway can become a bottleneck or SPOF (single point of failure). |
Use Federation when:
You have multiple teams working on different domains (e.g., user, orders, products).
You want to avoid monolithic GraphQL servers.
You’re already on a microservices architecture and need a clean API layer.
You need to enable schema composition and controlled entity extension.
Avoid Federation when:
You have a small team or a small monolithic app.
Your microservices don't share much schema or are loosely coupled.
You’re not familiar with GraphQL or don’t have time to invest in tooling/setup.
GraphQL Federation brings structure, scalability, and clarity to the chaos of microservice APIs. It aligns perfectly with the modular development goals of backend teams, while keeping the developer experience smooth on both server and client ends.
If you're building a microservices architecture or already using GraphQL, federation is worth exploring—especially with tools like Apollo Federation leading the way.
👉 Ready to federate your GraphQL APIs?
Start small—break one schema into subgraphs and try running a gateway locally. You’ll see the power of Federation in action.
Don’t forget to share this post with your team and bookmark it for reference!