Claude Code for GraphQL Federation: Subgraphs, Gateway, and Distributed Schema — Claude Skills 360 Blog
Blog / Backend / Claude Code for GraphQL Federation: Subgraphs, Gateway, and Distributed Schema
Backend

Claude Code for GraphQL Federation: Subgraphs, Gateway, and Distributed Schema

Published: October 14, 2026
Read time: 9 min read
By: Claude Skills 360

GraphQL Federation composes multiple GraphQL services into a single supergraph. Each team owns a subgraph — a GraphQL service that handles their domain’s types and queries. The Apollo Router (or gateway) merges them into one schema that clients query. Federation solves the problem of teams wanting independent GraphQL APIs that still appear unified to the client. Claude Code writes subgraph schemas, implements entity resolvers, and configures the router.

CLAUDE.md for GraphQL Federation Projects

## GraphQL Federation Stack
- Federation: Apollo Federation v2
- Router: Apollo Router (Rust-based, replace JS gateway for production)
- Subgraph framework: Apollo Server 4 (Node.js) or Hot Chocolate (C#/.NET)
- Schema management: Apollo Schema Registry (GraphOS)
- Auth: JWT validated at router level, user context forwarded to subgraphs
- Query planning: enabled by default in Apollo Router
- Testing: @apollo/subgraph + jest for unit; rover subgraph check for CI

Subgraph: Orders Service

// orders-service/src/schema.ts
import { buildSubgraphSchema } from '@apollo/subgraph';
import gql from 'graphql-tag';

export const typeDefs = gql`
  extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@external", "@requires", "@provides", "@shareable"])

  # This subgraph owns the Order type
  type Order @key(fields: "id") {
    id: ID!
    customerId: ID!
    status: OrderStatus!
    totalCents: Int!
    items: [OrderItem!]!
    createdAt: String!
    
    # This service provides the Customer via the customers subgraph's @key
    customer: Customer!
  }
  
  type OrderItem {
    productId: ID!
    quantity: Int!
    unitPriceCents: Int!
    # Product comes from the products subgraph
    product: Product!
  }
  
  # Stub types for entities owned by other subgraphs
  type Customer @key(fields: "id", resolvable: false) {
    id: ID!
  }
  
  type Product @key(fields: "id", resolvable: false) {
    id: ID!
  }
  
  enum OrderStatus {
    PENDING
    CONFIRMED
    SHIPPED
    DELIVERED
    CANCELLED
  }
  
  type Query {
    order(id: ID!): Order
    orders(customerId: ID!, first: Int = 20, after: String): OrderConnection!
  }
  
  type Mutation {
    placeOrder(input: PlaceOrderInput!): PlaceOrderPayload!
    cancelOrder(orderId: ID!, reason: String!): CancelOrderPayload!
  }
  
  # ... Connection/Input/Payload types ...
`;
// orders-service/src/resolvers.ts
export const resolvers = {
  Query: {
    order: async (_: any, { id }: { id: string }, ctx: Context) => {
      return ctx.db.orders.findById(id);
    },
    
    orders: async (_: any, { customerId, first, after }: any, ctx: Context) => {
      return ctx.db.orders.findByCustomer(customerId, { first, after });
    },
  },
  
  Mutation: {
    placeOrder: async (_: any, { input }: any, ctx: Context) => {
      if (!ctx.userId) throw new GraphQLError('Not authenticated', {
        extensions: { code: 'UNAUTHENTICATED' },
      });
      
      const order = await placeOrderService(ctx.db, input, ctx.userId);
      return { order, success: true };
    },
  },
  
  Order: {
    // Entity resolver: when other subgraphs ask for Order by id
    __resolveReference: async ({ id }: { id: string }, ctx: Context) => {
      return ctx.db.orders.findById(id);
    },
    
    // Resolve the customer (foreign key → entity reference for customers subgraph)
    customer: (order: Order) => {
      // Return a stub with just the key — router fetches the rest from customers subgraph
      return { __typename: 'Customer', id: order.customerId };
    },
    
    // Resolve order items
    items: async (order: Order, _: any, ctx: Context) => {
      return ctx.db.orderItems.findByOrderId(order.id);
    },
  },
  
  OrderItem: {
    product: (item: OrderItem) => ({
      __typename: 'Product',
      id: item.productId,
    }),
  },
};

Subgraph: Customers Service

// customers-service/src/schema.ts — owns Customer type
export const typeDefs = gql`
  extend schema
    @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])

  type Customer @key(fields: "id") {
    id: ID!
    email: String!
    name: String!
    plan: CustomerPlan!
    
    # Computed by this subgraph when orders subgraph references a Customer
    # @external: declared here, provided by orders subgraph
    # @requires: need orderCount to compute loyaltyTier
    orderCount: Int @external
    loyaltyTier: LoyaltyTier @requires(fields: "orderCount")
  }
  
  enum CustomerPlan { FREE PRO ENTERPRISE }
  enum LoyaltyTier { BRONZE SILVER GOLD PLATINUM }

  type Query {
    customer(id: ID!): Customer
    me: Customer
  }
`;

export const resolvers = {
  Customer: {
    __resolveReference: async ({ id }: { id: string }, ctx: Context) => {
      return ctx.db.customers.findById(id);
    },
    
    // loyaltyTier uses the orderCount provided by orders subgraph via @requires
    loyaltyTier: (customer: any) => {
      const count = customer.orderCount ?? 0;
      if (count >= 100) return 'PLATINUM';
      if (count >= 50) return 'GOLD';
      if (count >= 10) return 'SILVER';
      return 'BRONZE';
    },
  },
  
  Query: {
    customer: (_: any, { id }: any, ctx: Context) => ctx.db.customers.findById(id),
    me: (_: any, __: any, ctx: Context) => {
      if (!ctx.userId) throw new GraphQLError('Not authenticated');
      return ctx.db.customers.findById(ctx.userId);
    },
  },
};

Apollo Router Configuration

# router.yaml
supergraph:
  listen: 0.0.0.0:4000
  # Supergraph schema from Apollo GraphOS (managed federation)
  # Or use rover supergraph compose for self-managed

headers:
  all:
    request:
      - propagate:
          matching: x-request-id  # Forward request IDs to subgraphs
  subgraphs:
    orders:
      request:
        - insert:
            name: "x-internal-service"
            value: "router"

# Auth: validate JWT at router, forward user ID to subgraphs
authentication:
  router:
    jwt:
      jwks:
        - url: https://auth.myapp.com/.well-known/jwks.json

authorization:
  require_authentication: false  # Set true to require auth globally

# Coprocessor: custom auth/rate limiting
# coprocessor:
#   url: http://auth-service:9001

# Performance
traffic_shaping:
  router:
    timeout: 30s
  all:
    request:
      timeout: 25s
    deduplicate_query: true  # Dedup identical concurrent queries

# Telemetry
telemetry:
  exporters:
    tracing:
      otlp:
        endpoint: http://otel-collector:4317
    metrics:
      prometheus:
        enabled: true
        listen: 0.0.0.0:9090
        path: /metrics

Schema CI with Rover

# .github/workflows/schema-check.yml
- name: Check Orders Subgraph Schema
  run: |
    rover subgraph check myorg@production \
      --name orders \
      --schema ./orders-service/schema.graphql \
      --watch-delay 2
  env:
    APOLLO_KEY: ${{ secrets.APOLLO_KEY }}

- name: Publish Subgraph Schema
  if: github.ref == 'refs/heads/main'
  run: |
    rover subgraph publish myorg@production \
      --name orders \
      --schema ./orders-service/schema.graphql \
      --routing-url https://orders.internal.myapp.com/graphql
  env:
    APOLLO_KEY: ${{ secrets.APOLLO_KEY }}

@defer for Streaming

// Client: use @defer for non-critical fields
const CUSTOMER_WITH_ORDERS = gql`
  query CustomerDashboard($id: ID!) {
    customer(id: $id) {
      id
      name
      email
      # Defer the expensive order history
      ... on Customer @defer {
        recentOrders {
          id
          status
          totalCents
        }
        loyaltyTier
      }
    }
  }
`;

// React: handle incremental delivery
function CustomerDashboard({ customerId }) {
  const { data, loading } = useQuery(CUSTOMER_WITH_ORDERS, {
    variables: { id: customerId },
  });
  
  return (
    <div>
      {/* Renders immediately when available */}
      <h1>{data?.customer.name}</h1>
      <p>{data?.customer.email}</p>
      
      {/* Renders when deferred chunk arrives */}
      {data?.customer.recentOrders ? (
        <OrderList orders={data.customer.recentOrders} />
      ) : (
        <OrderListSkeleton />
      )}
    </div>
  );
}

For the REST APIs that often coexist with GraphQL Federation in larger systems, see the Go microservices guide for HTTP service patterns. For the authentication layer that the Apollo Router integrates with, the OAuth2 guide covers JWT validation. The Claude Skills 360 bundle includes GraphQL skill sets covering Federation v2 subgraphs, entity resolution, and router configuration. Start with the free tier to try Federation schema generation.

Keep Reading

Backend

Claude Code for Bun: Fast JavaScript Runtime and Toolkit

Build with Bun and Claude Code — Bun.serve for HTTP servers, Bun.file for fast file I/O, Bun.$ for shell commands, Bun.sql for SQLite and PostgreSQL, Bun.build for bundling, bun:test for testing, Bun.hash for hashing, bun.lock for deterministic installs, bun run for package.json scripts, hot reloading with --hot, bun init for project scaffolding, and compatibility with Node.js modules.

6 min read Jun 13, 2027
Backend

Claude Code for Express.js Advanced: Patterns for Production APIs

Advanced Express.js patterns with Claude Code — typed request handlers with RequestHandler generics, async error handling middleware, Zod validation middleware factory, rate limiting with express-rate-limit and Redis store, helmet security middleware, compression, dependency injection with tsyringe, file upload with multer and S3, pagination utilities, JWT middleware, and structured logging with pino.

6 min read Jun 8, 2027
Backend

Claude Code for KeystoneJS: Node.js CMS and App Framework

Build full-stack apps with KeystoneJS and Claude Code — config with lists, fields.text and fields.relationship for schema definition, access control with isAuthenticated and isAdmin functions, hooks with beforeOperation and afterOperation, GraphQL API auto-generation from schema, AdminUI for content management, session with statelessSessions, Prisma adapter for database, file storage with images and files fields, and custom REST endpoints.

6 min read Jun 7, 2027

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free