🚀 Understanding GraphQL Federation in Microservices Architecture

Gaurav KumarGaurav Kumar
8 min read

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.

🧩 What Is GraphQL Federation?

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.

Key Components:

ComponentDescription
SubgraphAn individual GraphQL service with part of the overall schema
Federated GatewayThe GraphQL server that stitches all subgraphs into one unified schema
@key DirectiveUsed to define the primary key for an entity shared across subgraphs
@requires / @providesManage dependency fields between subgraphs

🔍 Core Concepts Explained

1. Entity Resolution with @key

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
}

2. Service Extension with @extends

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]
}

3. Gateway Composition

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.

💡 Real-World Example: E-Commerce Platform

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.

🔹 Schema in User Service:

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.

🔹 Schema in Product Service:

type Product @key(fields: "id") {
  id: ID!
  name: String
  price: Float
}

Each product has its own ID, name, and price.

🔹 Schema in Order Service:

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.

🧪 Unified Query at the Gateway:

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.

🚦 How Federation Makes This Work

  • 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.

⚙️ Setting Up Apollo Federation (Simplified Steps)

To federate your services using Apollo Federation, follow these steps:

🔧 Step 1: Set Up Each Subgraph (User, Product, Order)

Each service is an independent GraphQL server using the @apollo/subgraph package.

1.1 Install Dependencies

npm install @apollo/subgraph graphql

👤 User Service

Schema (user-schema.graphql)

type User @key(fields: "id") {
  id: ID!
  name: String
  email: String
}

Server Setup (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 Service

Schema (product-schema.graphql)

type Product @key(fields: "id") {
  id: ID!
  name: String
  price: Float
}

Server Setup (index.js)

Use the same @apollo/subgraph setup, listening on port 4002.

📑 Order Service

This one extends both User and Product entities.

Schema (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]
}

Server Setup

Use the same @apollo/subgraph setup, listening on port 4003.

🛠 Step 2: Set Up Apollo Gateway

This service composes the subgraphs and exposes one unified schema.

Install Required Packages

npm install @apollo/gateway graphql @apollo/server

Gateway Setup (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}`);
});

🔁 Step 3: Start All Services

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!

🧪 Step 4: Query the Federated Schema

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!

⚖️ Pros and Cons of Using GraphQL Federation

Before adopting GraphQL Federation in your architecture, it’s important to weigh its advantages and potential challenges. Here’s a balanced look:

✅ Pros of GraphQL Federation

BenefitDescription
Modular ArchitectureEach subgraph service is owned and maintained by individual teams. This promotes autonomy and scalability.
Single Unified GraphThe client interacts with one clean, unified API—regardless of how many services are involved behind the scenes.
Independent DeploymentSubgraphs can be deployed independently without needing to rebuild or restart the gateway or other services.
Schema CollaborationTeams can contribute to shared entities (e.g., User, Product) using directives like @extends and @key, enabling tight yet controlled coupling.
Optimized Developer ExperienceGreat tools from Apollo like Rover, schema registry, and schema checks make collaboration and CI/CD smooth.
Frontend SimplicityFrontend developers can query complex relationships in a single request, improving developer productivity and reducing over-fetching.

⚠️ Cons of GraphQL Federation

LimitationDescription
Increased Operational ComplexityManaging multiple subgraph services and the gateway adds overhead to DevOps and deployment pipelines.
Cross-Team CoordinationSchema design requires coordination across teams when extending shared entities, especially in larger orgs.
Performance BottlenecksPoorly designed federated queries can result in N+1 problems or excessive network calls between services. Caching and batching become more critical.
Learning CurveDevelopers must understand GraphQL directives (@key, @extends, etc.), entity resolution, and subgraph architecture.
Debugging Can Be TrickyWhen things break, it can be harder to trace errors across subgraphs and the gateway.
Gateway is a Single Point of FailureUnless properly scaled and load-balanced, the Apollo Gateway can become a bottleneck or SPOF (single point of failure).

🧠 When to Use GraphQL Federation

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.

🎯 Conclusion: Future-Proof Your Backend

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!

0
Subscribe to my newsletter

Read articles from Gaurav Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Gaurav Kumar
Gaurav Kumar

Hey! I'm Gaurav, a tech writer who's all about MERN, Next.js, and GraphQL. I love breaking down complex concepts into easy-to-understand articles. I've got a solid grip on MongoDB, Express.js, React, Node.js, and Next.js to supercharge app performance and user experiences. And let me tell you, GraphQL is a game-changer for data retrieval and manipulation. I've had the opportunity to share my knowledge through tutorials and best practices in top tech publications. My mission? Empowering developers and building a supportive community. Let's level up together with my insightful articles that'll help you create top-notch applications!