GraphQL federation

Ask about this Page
Copy for AI
View as Markdown

Understand the federation concepts you need to write extensions.

The Commerce Integration Layer builds your Project's API with GraphQL federation. Several independent GraphQL services, called subgraphs, are composed into one schema that clients query as a whole. You extend your Project's API by adding a subgraph of your own, so a few federation concepts are important to understand before you write an extension.

Subgraphs and the supergraph

A subgraph is a single GraphQL service that owns part of the overall schema. The Commerce Integration Layer's core subgraph owns the shopper-facing schema, which includes the catalog, cart, checkout, orders, accounts, and B2B. Your extension is a second subgraph that you write and publish.

Composition merges the subgraphs into one supergraph, which is the schema clients actually query. Your storefront sends one query to the merged API and never sees the subgraph boundaries.

The router and the query planner

The router serves the supergraph at the public edge. When a query arrives, its query planner works out which subgraph owns each requested field, fetches from each subgraph in the right order, and stitches the results into one response. This is why a single query can select a core-subgraph field (a product's name) and an extension field (a field you added) side by side, because the planner routes each to its owner and merges them.
You don't write plans; you declare what your subgraph owns and what it needs, and the planner figures out the rest.

Entities

An entity is a type that more than one subgraph can contribute to, identified by a key. The core subgraph declares its top-level resources, which include Product, Cart, Order, Customer, and others, as entities keyed by id. That's what lets your subgraph attach a field to Product without redefining the whole type: you re-declare the entity with its key and your new field, and composition merges your field into the shared type.
type Product @key(fields: "id") {
  id: ID!            # the key that identifies the entity
  loyaltyPoints: Int! # your new field, merged into the shared Product
}

The key does two jobs:

  • it tells the composition these are the same Product across subgraphs.
  • it works as the handle the router uses to fetch the rest of the entity from its owner.
See the entity catalog for the full list of extensible types.

Entity references (stubs)

Because the router can fetch an entity from its owner by key, a resolver that returns an entity only needs to return the key, which is a stub like { id }. The router then resolves whatever other fields the client asked for from the core subgraph.
When your field returns a Product (or a list of them), return just the ids and let the router fill in the rest. Your subgraph decides which entities to return and in what order. The Commerce Integration Layer stays the source of truth for their contents. The type that resolves entity stubs back to full objects is called the join target, which is the core subgraph for the Commerce Integration Layer.

Directives

Federation directives are how each subgraph declares its role in the composed schema. These are the ones you use when writing extensions.

DirectiveWhat it declares
@linkImports the federation spec and the directives you use. Always the first line of your typeDefs.
@key(fields: "…")Marks a type as an entity and names the field(s) that identify it. Re-declare the key field normally (not @external).
@externalMarks a field as owned by another subgraph. You reference it for @requires but never resolve it. Never put it on the key field.
@requires(fields: "…")Declares that your resolver needs other (Commerce Integration Layer-owned) fields as input. The planner fetches them and delivers them on your resolver's parent.
@override(from: "integration-layer")Takes over ownership of an existing field, so your subgraph resolves it instead of the core subgraph. from must be "integration-layer", and the field must be one the core subgraph resolves.
@shareableLets a field be owned by more than one subgraph. This should be rarely needed, prefer adding a new field.
Use @override sparingly. Taking over a field the core subgraph already serves means your extension is responsible for reproducing its behavior, and it only composes safely when the field's result types are its own. In almost all cases, prefer adding a new field and, if you need existing data as input, pulling it in with @requires.
As much as possible, add new fields rather than redefine existing ones. When a field needs Commerce Integration Layer data as input, pull it in with @requires instead of resolving it yourself. This keeps the commercetools read inside the trust boundary. For the concrete SDL and resolver for each pattern, see Write schema extensions.

Composition and validation

Composition only succeeds if the subgraphs agree. Two subgraphs can't define the same field with different shapes, and a type an extension references must line up with the core subgraph's definition (for example, matching nullability on an @external field). When you validate or publish an extension, the Commerce Integration Layer composes it with your Project's live core subgraph and rejects anything that doesn't compose before it goes live.

Fields you add stay yours

The core subgraph grows over time, and it may one day add a field your extension already adds, such as Product.warranty. When it does, your field keeps resolving from your extension: the schema still composes, and clients see no change. You don't need to write anything for this. The Commerce Integration Layer marks every field your extension attaches to a core type as owned by your extension.
The reverse is not automatic. A field the core subgraph already serves can't be added by an extension by accident: publishing such a field fails with a message naming it. To use the name anyway, either choose a different field name, or take the field over deliberately with @override(from: "integration-layer").

Further reading

Read more about how to apply these concepts: schema mechanics, resolver patterns and publishing in Write schema extensions. See the entities the core subgraph exposes and the API's entry points in Experience API overview.