Skip to content
Feb 28

GraphQL Federation

MT
Mindli Team

AI-Generated Content

GraphQL Federation

Modern applications often need data from many different sources—user profiles, product catalogs, order histories, and more. Managing a single, gigantic GraphQL schema for all this becomes a bottleneck for development and deployment. GraphQL Federation solves this by allowing you to combine multiple independent GraphQL services into a single, unified API. This architecture gives client applications the simplicity of one endpoint while empowering backend teams to develop, deploy, and scale their services autonomously.

The Core Problem: Monolith vs. Microservices

In a traditional monolithic GraphQL server, all types, resolvers, and data sources are contained within one codebase. While simple to start, this model becomes difficult to scale as your organization grows. Different teams become entangled in a single release process, and the schema can become a tangled web of interdependencies.

GraphQL Federation adopts a microservices mindset for GraphQL. Instead of one monolith, you have multiple subgraph services. Each subgraph is a fully functional GraphQL service that owns a specific domain of your business logic and data—like Users, Products, or Reviews. The key innovation of federation is that these separate services can collaborate to define what appears to clients as one seamless graph.

Key Architecture: Subgraphs and the Gateway

A federated architecture has two primary components: subgraphs and a gateway.

A subgraph is an independent GraphQL service that defines part of the overall schema. Crucially, each subgraph owns specific types and fields. For example, a Users subgraph would define the User type with fields like id, name, and email. It is responsible for resolving all data for the types it owns.

The gateway (sometimes called the federated gateway or router) sits between the clients and the subgraphs. Its job is composition and query planning. During startup, it collects each subgraph's schema. Using special federation directives, it intelligently composes them into one supergraph schema. When a client sends a query, the gateway analyzes it, breaks it into parts, and routes each part to the appropriate subgraph service. It then assembles the results before sending the final response back to the client.

This separation means a team managing the Products service can update its schema and deploy independently, without coordinating with the Orders team. The gateway recomposes the supergraph automatically.

Understanding Entities and Type Ownership

The magic that allows types from different services to connect is the entity. An entity is a type that can be extended and referenced by multiple subgraphs, but is owned by exactly one.

You define an entity in its owning subgraph using the @key directive. This directive specifies the primary key field (like id) that other subgraphs will use to reference an instance of that entity.

# In the Users subgraph (Owner)
type User @key(fields: "id") {
  id: ID!
  name: String!
  email: String!
}

Another subgraph can then extend this entity to add fields that are relevant to its own domain. It does this by defining a reference resolver for that entity.

# In the Reviews subgraph (Extending)
extend type User @key(fields: "id") {
  id: ID! @external
  reviews: [Review!]!
}

Here, the Reviews subgraph extends the User type to add a reviews field. It declares the id field as @external because it comes from another service. When the gateway gets a query for a user's reviews, it will first fetch the id from the Users subgraph and then pass that id to the Reviews subgraph's resolver to fetch the reviews list. This mechanism is how the graph is "stitched" together across service boundaries.

The Benefits: Autonomy and a Unified Interface

The primary benefit of GraphQL Federation is team autonomy. Development teams can focus on their specific business domain, choose their own technology stack, and deploy on their own schedule. They own their subgraph's entire lifecycle.

For client developers, the complexity of multiple endpoints disappears. They interact with a single, powerful GraphQL API that provides a complete view of all available data. They can write queries that seamlessly span data from multiple services without needing to know where that data lives.

# Client Query - Spans Users and Reviews services
query GetUserWithReviews($userId: ID!) {
  user(id: $userId) {
    name   # From Users subgraph
    email  # From Users subgraph
    reviews { # From Reviews subgraph
      text
      rating
    }
  }
}

This model scales organizationally and technically, as subgraphs can be scaled independently based on their specific load.

Common Pitfalls

  1. Over-Federation (Creating Too Many Subgraphs): It's tempting to make every microservice a subgraph. However, this can introduce unnecessary network latency and gateway complexity for types that are truly cohesive and always queried together. Start with broader domain boundaries (e.g., a Commerce subgraph for products, inventory, and categories) and split later if needed.
  • Correction: Design subgraphs around bounded contexts and data access patterns, not just technical service boundaries. Keep types that are highly interdependent within the same subgraph.
  1. Circular Dependencies Between Subgraphs: A Users subgraph extending Product while the Products subgraph extends User creates a composition loop that the gateway cannot resolve.
  • Correction: Model your schema to avoid bidirectional extensions. Often, this indicates a needed third entity or a design where one relationship should be owned by a single service. Use a shared understanding of entity ownership to keep references flowing in one primary direction.
  1. Ignoring Performance of Reference Resolvers: A query for 100 products, each requiring a call to a Inventory subgraph to get stock level, can result in 101 separate network calls (1 for products + 100 for inventory)—the classic N+1 problem.
  • Correction: Implement data loader patterns within your subgraphs to batch these reference resolver calls. Advanced gateways also offer features to batch requests automatically to mitigate this issue.
  1. Incorrect Type Ownership: Assigning ownership of a core type like User to multiple subgraphs leads to conflicts and undefined behavior during schema composition.
  • Correction: Clearly define and document type ownership from the outset. An entity has one, and only one, owning subgraph. All other subgraphs must only extend it.

Summary

  • GraphQL Federation composes multiple independent GraphQL services (subgraphs) into one unified supergraph API, managed by a gateway.
  • It enables development team autonomy, allowing services to be built, deployed, and scaled independently.
  • The architecture relies on entities—types owned by one subgraph but extendable by others using the @key directive and reference resolvers.
  • The gateway handles query planning, routing query fragments to the correct subgraphs and stitching the results together.
  • Successful federation requires careful design around domain boundaries, type ownership, and performance optimization to avoid common pitfalls like over-federation and N+1 query problems.

Write better notes with AI

Mindli helps you capture, organize, and master any subject with AI-powered summaries and flashcards.