skip to content

In Apollo Federation, how do the subgraph, supergraph and API schemas differ?

level: juniorimportance: must knowfreq 58%

answer

  1. Three documents, not one
  2. One is written by hand per service
  3. One is composed for the router
  4. One is what a client introspects
  5. Ownership metadata lives in the middle one

basics

~20 s

Each service publishes its own subgraph SDL. Composition merges those into one supergraph schema that also records which service owns each field. The API schema is that same graph with all federation machinery stripped out - the only one clients introspect.

solid answer

~40 s

Federation produces three documents. A **subgraph schema** is what one service publishes: its own types and fields plus federation directives such as `@key` declaring how its types join to the rest of the graph. **Composition** merges every subgraph schema into one **supergraph schema** — the whole graph plus routing metadata written as `join__` directives recording which subgraph declares each type and field, and where each service lives. That document is the router's input and never leaves the platform. Removing the federation machinery from it leaves the **API schema**: an ordinary GraphQL schema with no `@key`, no `join__` directives and nothing marked `@inaccessible`. Clients introspect and write documents against the API schema, and cannot tell from it how many services sit behind the endpoint.

code

graphql · 24 lines
graphql
# registry subgraph
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])

type Animal @key(fields: "id") {
  id: ID!
  name: String!
  birthDate: Date!
}

type Query {
  animal(id: ID!): Animal
}

# breeding subgraph
extend schema
  @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"])

type Animal @key(fields: "id") {
  id: ID!
  sire: Animal
  dam: Animal
  offspring: [Animal!]!
}

go deeper

for a junior

Be ready to name all three documents and say who reads each: a service publishes its subgraph SDL, the router consumes the composed supergraph, the client introspects the API schema. That naming alone is what this screening question checks.

for a middle

Explain the mechanics of the derivation: composition merges same-named types rather than concatenating files, the supergraph adds routing metadata, and the API schema is the supergraph minus federation directives and minus anything marked inaccessible.

for a senior

Show you know which document each check and each deploy step operates on, and that a supergraph change can leave the API schema identical. Be able to say what you would look at first when a team asks which service is behind a field.

for a principal

Own the artefact policy: who publishes the supergraph, how it is versioned and rolled back, and whether the API schema is a reviewed release with consumers or a by-product nobody looks at until something breaks.

## Three documents, produced at three different moments A federated graph is not one schema. It is three, and interviewers ask this first because a candidate who cannot separate them cannot reason about anything else in federation — not deploys, not breaking changes, not what a client is actually allowed to ask for. Take a livestock pedigree graph split across three services. A **registry** service owns an animal's identity: its herd book number, name and birth date. A **breeding** service owns lineage: sire, dam, offspring. A **shows** service owns competition results. All three describe the same conceptual `Animal`, and a client wants to select across all three in one document without knowing any of this exists. ### 1. The subgraph schema — hand-written, one per service Each service publishes its own SDL. It contains only that service's types and fields, plus federation directives declaring how its types join to the rest of the graph. The registry service declares `Animal` with a key; the breeding service declares its *own* `Animal` with the same key and a completely different set of fields. Neither service knows the other exists — that is the point of the arrangement. The federation directives themselves are imported into the subgraph's namespace by an `@link` on the schema definition, which names the federation specification URL and version. This is why two subgraphs can be on different federation versions and still compose. ### 2. The supergraph schema — composed, one per graph **Composition** reads every subgraph schema and merges them into a single document. Merging is not concatenation. One `Animal` type comes out, carrying the union of the fields the subgraphs declared, and composition fails outright if the declarations cannot be reconciled. What makes the output a *supergraph* rather than just a merged schema is the routing metadata composition adds. Every merged element is annotated with `join__` directives recording which subgraph declared it and, for entities, what key reaches it; a generated `join__Graph` enum lists each subgraph by name and URL. A router loads this one document and can plan any incoming operation from it alone — which service to call for which field, and what key fields to send — without ever introspecting a subgraph at runtime. The supergraph is a build artefact. Nobody edits it by hand, and it is not meant to leave the platform. ### 3. The API schema — derived, one per graph, the only public one Strip the federation machinery out of the supergraph and you have the **API schema**: an ordinary GraphQL schema, indistinguishable from one a single monolithic server would serve. No `@key`, no `@join__type`, no `join__Graph` enum, no `_entities` or `_service` root field. Anything marked `@inaccessible` is removed entirely, so a field can exist in the supergraph for the router's internal use and be absent from the client's view of the graph. This is the document a router answers introspection with, the one a typed client generator should be fed, and the one your API's consumers write documents against. ```graphql # API schema — what a client introspects type Animal { id: ID! name: String! birthDate: Date! sire: Animal dam: Animal offspring: [Animal!]! showResults: [ShowResult!]! } ``` Three services produced that type. Nothing in it says so. ## Why the separation matters in practice **Different audiences.** Subgraph SDL is owned and reviewed by one team. The supergraph is owned by the platform: it is the router's input and the artefact you roll forward or back when routing changes. The API schema is the contract with people outside the organisation entirely. **Different failure modes.** A subgraph schema can be perfectly valid on its own and still fail composition. A supergraph can compose cleanly and still represent a client-breaking API schema. Knowing which document a check ran against tells you what the green tick actually proved. **Different change rates.** Moving a subgraph's URL, or moving a field's ownership from one service to another, rewrites the supergraph and leaves the API schema byte-identical. Clients see nothing; latency may change a great deal. ## A note on what is specified The GraphQL specification defines none of this. It defines the type system, the document language and the execution algorithm for *one* schema. Subgraph directives, composition, the supergraph document and the derivation of the API schema all come from Apollo Federation, a separate composition specification layered on top of ordinary GraphQL. That layering is exactly why the API schema is plain GraphQL: everything federation added has been removed by the time a client looks.

  • Which of the three schemas does a client's introspection query return?
    The API schema. A federation router answers introspection with the client-facing schema, so `@key`, the `join__` directives and the `join__Graph` enum are all absent, and so are the federation root fields the router uses to fetch entities. The supergraph document stays inside the platform as the router's configuration; nothing in a normal response tells a client which subgraph produced a given field.
  • What happens to a field marked @inaccessible during composition?
    It survives into the supergraph, so the router can still use it internally — as part of a key, for example — but it is removed when the API schema is derived, so clients cannot select it and it does not appear in introspection. Composition fails if the resulting API schema would be invalid, such as an accessible field whose type is inaccessible.
  • Could you serve the supergraph document directly as your public schema?
    It parses as valid SDL, but you should not. It exposes the internal subgraph names and URLs, the `join__` machinery clients have no use for, and any element that was deliberately marked inaccessible. It is also not executable by any single service: it describes a graph whose fields are spread across several servers, which is why a router plans against it rather than resolving from it.

The subgraph schemas are the draft chapters, the supergraph is the editor's master copy with a margin note on every line saying who wrote it, and the API schema is the printed book the reader buys.

saying these in an interview costs you the question

  • Thinks clients introspect the supergraph schema
  • Says composition just concatenates the subgraph SDL
  • Believes the API schema still contains @key
  • Cannot say which document the router consumes
  • Assumes every subgraph must define every type
  • Thinks the supergraph document is hand-written

context