Learn GraphQL - Microservices Architecture Patterns
Episode 36 of 51

Learn GraphQL - Microservices Architecture Patterns

Episode 36 builds GraphQL architecture with microservices: GraphQL Gateway patterns, a federation deep dive for cross-service entity resolution, event-driven architecture with event sourcing and CQRS, message broker integration like Kafka and RabbitMQ, and service discovery.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Microservices give you deploy and scale freedom per domain — but bring new complexity: split data, inter-service communication, and consistency. Episode 36 connects GraphQL with the world of microservices comprehensively.

We'll cover gateway patterns, a federation deep dive, event-driven architecture, message broker integration, and service discovery.

Microservices Patterns

GraphQL Gateway for Microservices

In episode 22 you built federation. This pattern is the foundation of GraphQL for microservices: each service has its own subgraph, and a gateway unites them into one schema for clients.

The key to success is clean domain boundaries:

  • Each service has clear data and schema ownership.
  • Inter-service contracts are explicit via federation directives.
  • No service accesses another service's database directly.
GraphQL with microservices
gateway
  -> user-service (subgraph users)
  -> order-service (subgraph orders)
  -> payment-service (subgraph payments)

Inter-Service Communication

Inter-service communication uses two main patterns: synchronous (direct HTTP/gRPC calls) and asynchronous (events through a message broker). GraphQL generally uses the first for queries, and the second for data consistency.

Apollo Federation Deep Dive

Entity Resolution and Optimization

Federation faces a unique challenge: one entity spread across many services. __resolveReference (episode 22) is the mechanism for assembling entities. Optimizations:

  • Make __resolveReference use DataLoader so references are batched.
  • Limit the number of @external fields — the more another service needs, the more expensive query planning.
  • Use @requires wisely so the gateway doesn't need to call many services.

Cross-Service Transactions and Monitoring

Cross-service transactions can't be guaranteed with ordinary ACID. The pattern used: saga — a sequence of steps with compensation when one fails. For monitoring, every subgraph sends traces to Apollo Studio (episode 24) so the journey of a single query across multiple services is clearly visible.

Event-Driven Architecture

Event Sourcing and CQRS

For domains that need a complete history, apply event sourcing: every change is stored as an immutable event, and the current state is derived from the event stream. CQRS separates the read model (GraphQL queries) from the write model (mutations and commands).

GraphQL on top of event sourcing
type OrderEvent {
  id: ID!
  type: String!
  occurredAt: DateTime!
  data: JSON!
}
 
type Query {
  orderEvents(orderId: ID!): [OrderEvent!]!
}

Benefits: a complete audit trail and historical queries. Complexity is high — only use it when you really need it.

Message Brokers: Kafka and RabbitMQ

Message brokers enable asynchronous inter-service communication; install the Kafka client with npm install kafkajs:

JSPublish and subscribe to events
import { Kafka } from "kafkajs";
 
const kafka = new Kafka({ brokers: ["localhost:9092"] });
const producer = kafka.producer();
const consumer = kafka.consumer({ groupId: "graphql-service" });
 
await producer.connect();
await producer.send({
  topic: "order.created",
  messages: [{ value: JSON.stringify(order) }],
});
 
await consumer.subscribe({ topic: "order.created" });
await consumer.run({
  eachMessage: async ({ message }) => {
    await handleOrderCreated(JSON.parse(message.value));
  },
});

The common pattern: a GraphQL mutation writes to the main database and publishes an event to the broker; other services listen for that event to sync their data (for example an analytics service). This is the foundation of eventual consistency.

Eventual Consistency

Because data is spread across many services, instant consistency is hard to achieve. The principle: the primary service responds to the client immediately, while derived (denormalized) data is synced via events. GraphQL on the client side must be ready to handle data that isn't "immediately" consistent — which is why the refetch and optimistic UI patterns (episode 25) are so useful.

Service Discovery

Consul and Kubernetes

In the world of microservices, services no longer have static addresses. Service discovery solves the "where is the other service" problem:

  • Kubernetes DNS: services are found via internal DNS names (user-service.default.svc.cluster.local).
  • Consul: services register themselves, clients find them via the discovery API.
Service discovery in Kubernetes
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - port: 4001
      targetPort: 4001

Federation gateways use service discovery to find subgraphs: instead of static URLs, subgraphs are registered and discovered dynamically. This lets you add or replace services without disturbing clients.

Conclusion

Key takeaways:

  • The federation gateway is the main GraphQL pattern for microservices.
  • __resolveReference with DataLoader and wise @requires keep performance up.
  • Saga and event sourcing manage cross-service consistency.
  • Message brokers like Kafka sync data between services asynchronously.
  • Eventual consistency requires clients to handle non-instant data.
  • Service discovery (Kubernetes, Consul) lets gateways find subgraphs dynamically.

In the next episode, episode 37, you'll learn about GraphQL and serverless architecture — serverless best practices like cold start optimization, AWS Lambda with API Gateway, edge computing with Cloudflare Workers and Vercel Edge, and database connection management with RDS Proxy and PlanetScale. Your GraphQL will run anywhere without servers!