# 🚀 Understanding GraphQL Federation in Microservices Architecture

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

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1745221622982/008c9db7-593c-4826-abce-457f21b748de.png align="center")

### Key Components:

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

# 🔍 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:

```graphql
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:

```graphql
# 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:

```graphql
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:

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

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

### 🔹 Schema in Order Service:

```graphql
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:

```graphql
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

```bash
npm install @apollo/subgraph graphql
```

### 👤 **User Service**

#### Schema (`user-schema.graphql`)

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

#### Server Setup (`index.js`)

```javascript
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`)

```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`)

```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

```bash
npm install @apollo/gateway graphql @apollo/server
```

#### Gateway Setup (`gateway.js`)

```javascript
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:

```bash
# 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`](http://localhost:4000/graphql) and unified!

### 🧪 Step 4: Query the Federated Schema

Test it with a powerful, nested query:

```graphql
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

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

### ⚠️ Cons of GraphQL Federation

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

### 🧠 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!**
