Explain the core federation directives @key, @external, @requires, and @provides.
answer
- @key = identity, enables sharing
- @external = field owned elsewhere
- @requires = pull owner data IN to compute
- @provides = push data OUT to skip a hop
- requires/provides fields must be @external
basics
~20 s@key names the field(s) that identify an entity so it can be shared across subgraphs. @external marks a field defined elsewhere. @requires says a resolver needs certain external fields. @provides promises a field is already available on a returned entity.
solid answer
~50 sThese federation directives declare how entities are shared and resolved across subgraphs. `@key(fields: "id")` marks an entity and the field set that uniquely identifies it, enabling the `_entities` reference resolver. When a subgraph extends an entity it doesn't own, it re-declares the entity with the same `@key` and marks fields it does not own but references as `@external`. `@requires(fields: "...")` on a field says: to resolve this field, the router must first fetch these external fields from the owning subgraph and pass them in — used for computed fields depending on data owned elsewhere. `@provides(fields: "...")` is an optimization: it tells the router that when this subgraph returns the entity through a particular path, it can already supply those normally-external fields, letting the router skip an extra hop. In Spring you declare these in the `.graphqls` SDL; `@key` types get `@EntityMapping` resolvers, and `@requires` fields receive the required data as arguments.
code
graphql · 22 linesextend schema @link(url: "https://specs.apollo.dev/federation/v2.3",
import: ["@key", "@external", "@requires", "@provides"])
# shipping subgraph extends Product (owned by catalog)
type Product @key(fields: "id") {
id: ID!
weight: Int @external
dimensions: Dimensions @external
# needs catalog-owned fields to compute:
shippingEstimate: Float @requires(fields: "weight dimensions")
}
# reviews subgraph can supply username inline, skipping the users subgraph
type Review @key(fields: "id") {
id: ID!
author: User @provides(fields: "username")
}
type User @key(fields: "id") {
id: ID!
username: String @external
}go deeper
Know @key identifies an entity; the others are advanced.
Explain @key and @external and roughly what extending a type means.
Correctly distinguish @requires (pull in) vs @provides (push out) with a concrete computed-field example.
Reason about query-plan/latency impact and data-consistency trade-offs of @requires/@provides across team boundaries.
## The mental model Federation lets a type be **owned** by one subgraph and **contributed to** by others. Directives express who owns what and what data must flow where. All are declared in SDL (in Spring, your `.graphqls`), imported through the `@link` to the federation spec. ## `@key(fields: "...")` Marks a type as a federated **entity** and specifies its identifying field(s). Example: `type Book @key(fields: "id")`. This is the foundation — without a `@key`, a type cannot be referenced across subgraphs, because the router would have no way to build a reference. Keys can be composite (`@key(fields: "storeId sku")`) or nested (`@key(fields: "id org { id }")`). A type may have multiple `@key`s. In Spring, each `@key` type needs an `@EntityMapping` method able to resolve the entity from those key fields. ## `@external` Used when a subgraph **references a field it does not own**. When subgraph B extends `Book` (owned by A) and needs to read A's `title`, it declares `title: String! @external`. This tells composition: "this field's source of truth is another subgraph; I'm only referencing it." It usually appears alongside `@requires` or `@provides`. ## `@requires(fields: "...")` Put on a field a subgraph resolves, when that resolution **depends on fields owned by another subgraph**. Example: a `shipping` subgraph computes `Product.shippingEstimate`, which needs `weight` and `dimensions` owned by the `catalog` subgraph: ```graphql type Product @key(fields: "id") { id: ID! weight: Int @external dimensions: Dimensions @external shippingEstimate: Float @requires(fields: "weight dimensions") } ``` The router fetches `weight`/`dimensions` from catalog first, then calls shipping's `_entities` with those values included in the representation so the resolver can compute the estimate. In Spring, those required fields arrive inside the representation map (or bound arguments). ## `@provides(fields: "...")` An **optimization hint**. It declares that when this subgraph returns an entity **via a specific field path**, it can already provide certain otherwise-external fields, so the router need not make a separate hop to the owning subgraph. Example: a `reviews` subgraph returning `Review.author: User` might `@provides(fields: "username")` because it happens to have the username inline. If the client only asks for `username`, the router skips calling the users subgraph. It's purely about reducing round-trips; correctness must still hold (the provided data must match the owner's). ## How they interact - `@key` is mandatory to make anything shareable. - `@external` marks borrowed fields. - `@requires` pulls owner data *into* a resolver. - `@provides` pushes owner data *out* early to save a hop. ## Gotchas - `@requires`/`@provides` reference fields that must be `@external` in that subgraph. - Overusing `@provides` risks stale/inconsistent data if the providing subgraph's copy drifts from the owner's. - `@requires` adds a dependency edge in the query plan — misuse can force extra sequential fetches and hurt latency. - Federation v1 used `@extends`/`extend type` heavily; v2 (via `@link`) lets you re-declare types with `@key` directly, but the directive semantics above are the same.
- Why must fields named in @requires be marked @external?Because the subgraph doesn't own them — they belong to another subgraph. @external declares that source of truth is elsewhere; @requires then asks the router to fetch and supply them.
- What's the risk of @provides?It bypasses the owning subgraph for those fields, so if the providing subgraph's copy is stale or diverges from the owner, clients get inconsistent data. It trades correctness safety for fewer round-trips.