Skip to content
All essays
ArchitectureFebruary 18, 202511 min

GraphQL Federation: Microservices Architecture

Learn GraphQL Federation for microservices. Build scalable distributed GraphQL APIs.

Ü
Ümit Uz
Mobile & Full Stack Developer

What is Federation?

Federation allows you to compose multiple GraphQL services into a single graph.

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

# Posts service
type Post {
  id: ID!
  title: String!
  content: String!
  author: User
}

extend type User @key(fields: "id") {
  id: ID! @external
  posts: [Post]
}

Apollo Federation

Subgraph Setup

javascript
// posts-service/index.js
import { ApolloServer } from '@apollo/server';
import { buildSubgraphSchema } from '@apollo/subgraph');

const typeDefs = gql`
  extend type User @key(fields: "id") {
    id: ID! @external
    posts: [Post]
  }

  type Post @key(fields: "id") {
    id: ID!
    title: String!
    author: User
  }
`;

const resolvers = {
  Post: {
    author(post) {
      return { __typename: 'User', id: post.authorId };
    }
  },
  User: {
    posts(user) {
      return db.posts.filter({ authorId: user.id });
    }
  }
};

const server = new ApolloServer({
  schema: buildSubgraphSchema([{ typeDefs, resolvers }])
});

Gateway Setup

javascript
// gateway/index.js
import { ApolloGateway } from '@apollo/gateway';
import { ApolloServer } from '@apollo/server';

const gateway = new ApolloGateway({
  supergraphSdl: new IntrospectAndCompose({
    subgraphs: [
      { name: 'users', url: 'http://localhost:4001' },
      { name: 'posts', url: 'http://localhost:4002' }
    ]
  })
});

const server = new ApolloServer({ gateway });

Federation Directives

@key

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

@requires

graphql
type Review @key(fields: "id") {
  id: ID!
  product: Product
  rating: Int
}

extend type Product @key(fields: "id") {
  id: ID! @external
  reviews: [Review]
  avgRating: Int @requires("price")
}

@provides

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

@external

graphql
extend type Product @key(fields: "sku") {
  sku: ID! @external
  price: Int @external
  weight: Int @external
}

Entity Resolver

javascript
const resolvers = {
  Product: {
    __resolveReference(reference) {
      return db.products.findBySku(reference.sku);
    }
  }
};

Query Planning

javascript
// Gateway automatically plans queries
# Query:
query GetProductWithReviews($id: ID!) {
  product(id: $id) {
    name
    reviews {
      rating
      author {
        name
      }
    }
  }
}

# Execution plan:
1. Products subgraph: product(id, name)
2. Reviews subgraph: reviews(product, rating)
3. Users subgraph: user(id, name)

Best Practices

  1. 1Separation of concerns: Each service owns its types
  2. 2Minimal coupling: Use @key sparingly
  3. 3Entity design: Choose primary keys carefully
  4. 4Performance: Monitor query planning overhead
  5. 5Testing: Test subgraphs independently

Schema Registry

bash
# Apollo Studio
# Publish subgraph schema
rover subgraph publish my-graph@current \
  --name products \
  --schema ./products/schema.graphql \
  --routing-url http://products-service:4001

Monitoring

javascript
// Trace query execution
const gateway = new ApolloGateway({
  supergraphSdl,
  // Collect tracing data
  plugins: [ApolloServerPluginUsageReporting()]
});

Build federated graphs at scale!

Related essays

Next essay
Git Mastery: Advanced Git Techniques