In a Federation 1 subgraph schema, what does the extend keyword on a type mean?
answer
- Two subgraphs mention one type
- Who defined it, who only adds to it
- A keyword meaning "not mine"
- Required in Federation 1, optional later
basics
~20 sThe extend keyword marks the type as owned by another subgraph: this schema only contributes extra fields to a type it did not define, so composition treats the two declarations as one type rather than a clash.
solid answer
~50 sIn Apollo Federation 1 every type had exactly one owning subgraph — the one that defined it outright. Any other subgraph that wanted to attach fields to it wrote `extend type Locker @key(fields: "id")` and marked the borrowed key fields `@external`, which told the composer "I am not defining Locker, I am hanging fields off it". Federation 2 dropped the requirement: every subgraph declares the type normally, composition merges the declarations, and `extend` became optional syntax accepted for compatibility. Federation 2 also stopped requiring `@external` on the key fields in that position, because it works out contributed versus owned fields from the composed picture instead of from a keyword. Reading an older subgraph, treat `extend` as a historical marker meaning "someone else owns this type" — it has never had any runtime behaviour of its own.
code
graphql · 11 lines# Federation 1 — Reservations contributes to a type it does not own
extend type Locker @key(fields: "id") {
id: ID! @external
activeHolds: Int!
}
# Federation 2 — same meaning, no keyword, no @external on the key
type Locker @key(fields: "id") {
id: ID!
activeHolds: Int!
}go deeper
Be ready to read a subgraph schema and say who owns the type. Seeing extend should immediately tell you this service only adds fields and another service defines the rest.
Explain what composition does with the two declarations, why the key had to be repeated and marked external in Federation 1, and what changed in Federation 2's merge model.
Know what this means for a migration: dropping the keyword is mechanical, but the real work is auditing which subgraph resolves which field once the syntax stops recording it.
Own the convention. Decide whether your organisation keeps Federation 1-style syntax during a long migration or normalises every subgraph, and how you keep type ownership discoverable once a keyword no longer states it.
## The problem the keyword existed to solve A federated graph is composed from several subgraph schemas that are written independently, usually in different repositories by different teams. Composition merges them into one supergraph schema. That merge has to answer one question about every type name it meets twice: are these two declarations of the same type, and if so, who is in charge of it? Apollo Federation 1 answered that with syntax. Exactly one subgraph *defined* a type. Every other subgraph that wanted to add fields to it *extended* it: ```graphql # Lockers subgraph — the owner type Locker @key(fields: "id") { id: ID! address: String! bankSize: Int! } # Reservations subgraph — a contributor extend type Locker @key(fields: "id") { id: ID! @external activeHolds: Int! } ``` The Reservations subgraph is not claiming `Locker`. It is saying: a type called `Locker` exists somewhere else, here is the key I will use to talk about instances of it, the key field `id` is not mine to resolve (`@external`), and I am adding one field, `activeHolds`, that I *do* resolve. Without `extend`, Federation 1 composition would have seen two definitions of `Locker` and treated the pair as a conflict. ## What it does not do Three misreadings are common enough to be worth naming. It is not a runtime instruction. Nothing is copied, fetched or proxied because of `extend`. It is a statement to the composer, consumed once when the supergraph is built; at request time the router works from the composed schema, which records field ownership directly. It does not import the owner's fields into this subgraph. The Reservations subgraph above cannot resolve `address`; it does not even know the field exists unless it re-declares it as `@external`. A contributor sees only what it writes down. It does not require a shared base schema file. The two documents are never concatenated. Each subgraph's SDL stands alone and is valid on its own — which is precisely why `extend` was needed as an explicit marker in the first place. This is also where the keyword differs from plain GraphQL type extensions, where `extend type` normally extends a definition present in the same document. ## Why Federation 2 dropped it Federation 2 changed the model from "one owner, several extenders" to "several declarations, composed". Every subgraph writes a plain `type Locker @key(fields: "id") { ... }` listing the key plus whatever fields it contributes, and composition merges them. Field-level ownership is still exactly one subgraph per field by default; what disappeared is the requirement to say in syntax which declaration came first. Two simplifications followed. The key fields in a contributing subgraph no longer need `@external`, because a subgraph that merely lists the key so it can be addressed is not making a competing claim on it. And `extend` itself became optional — a Federation 2 subgraph may still write it, and it composes identically to a plain definition, so migrations do not have to touch every type at once. ## What a reviewer should take from it If you open a subgraph and see `extend type` on a type, you are almost certainly looking at Federation 1-era SDL or at a schema migrated from it. That tells you something useful before you read another line: this file is a contributor, not the owner, so the fields you find in it are the only ones this service resolves, and anything else about that type lives in another repository. When you migrate the subgraph to Federation 2, dropping the keyword and the `@external` markers on the key fields is a mechanical change; the meaningful decisions — which subgraph resolves which field, and whether any field is resolved in more than one place — are made by the other ownership directives, not by this one.
- Without `extend`, how does Federation 2 composition tell a contributed field from an owned one?By looking at all the subgraphs at once rather than at a keyword in one of them. Each field in the merged type is attributed to the subgraph that declares it, and a field declared in two subgraphs is a conflict unless it is explicitly marked as shareable. Key fields are the exception: every subgraph that references the entity has to be able to return them, so they are resolvable in all of them.
- Is `extend type` still legal in a Federation 2 subgraph, and does it change anything?It is legal and composes identically to a plain type definition, which is what makes an incremental Federation 1 to 2 migration possible — you do not have to rewrite every contributor in one commit. It carries no extra meaning to the router, so in new SDL there is no reason to write it.
It is the difference between publishing a book and publishing a supplement to someone else's book: the supplement lists the title it attaches to, but ships no chapters of the original.
saying these in an interview costs you the question
- Says extend makes the router copy the owner's fields
- Thinks the contributing subgraph can resolve the owner's other fields
- Believes all subgraphs share one base schema file
- Claims Federation 2 rejects the extend keyword
- Confuses extend with taking over ownership of a field