skip to content

In GraphQL schema stitching, what does the gateway hold that the services do not?

level: juniorimportance: must knowfreq 53%

answer

  1. Ask who edits the file
  2. One side does not know it was joined
  3. Renames and delegation rules live somewhere
  4. Central configuration versus per-service declaration
  5. Neither is defined by the GraphQL specification

basics

~20 s

The gateway holds the merge configuration: renames that resolve name collisions, plus delegation rules saying which field on one service's type is answered by calling which operation on another. The stitched services stay ordinary GraphQL servers, unaware of each other.

solid answer

~50 s

Stitching puts **all** the cross-service knowledge in one place the gateway owns. The gateway fetches each service's schema, merges the type systems, and applies configuration written by whoever runs the gateway: rename this type because two services both call theirs `Seat`, hide that field, and resolve `Seat.price` by calling the fares service's `seatPrices` query with the parent's flight number and seat number. Neither service is changed, and neither knows it has been joined to anything. Composition inverts exactly that: each service publishes a schema that declares its own keys and its own contribution, a composition step merges those declarations, and nobody edits a central mapping. The practical difference is whose calendar a cross-service field lands on. Worth saying plainly: the GraphQL specification defines nothing about merging schemas — stitching is a library technique with no specification, and composition is standardised separately by the Apollo Federation specification.

code

pseudocode · 10 lines
pseudocode
# gateway configuration. Neither service's schema mentions the other.

rename fares_service.Seat -> FareRow          # collides with inventory's Seat

merge field Seat.price:
    from:      fares_service
    call:      seatPrices(keys: $keys)
    keys:      parent.flightNumber + ":" + parent.seatNumber
    match:     result.key == parent.flightNumber + ":" + parent.seatNumber
    take:      result.amountMinorUnits

go deeper

for a junior

Be ready to say, in one sentence each, that a stitched gateway holds the merge and delegation rules itself while a composed graph is assembled from declarations each service publishes. Naming where the join lives is most of the answer.

for a middle

An interviewer expects the mechanics: the gateway copies remote schemas, resolves name collisions by configuration, and delegates a field by calling another service with values taken from the resolved parent. Say plainly that GraphQL specifies none of this.

for a senior

Show that you read the choice as an ownership question. Explain what changes about review queues and release cadence when the mapping moves out of one central file into each service's own schema, and what stitching can still do that composition deliberately cannot.

for a principal

Own the framing that both routes give the client an identical endpoint, so the decision is entirely about which teams absorb the cost of cross-boundary change. Be ready to argue when the central-configuration model is still the cheaper answer.

## The question behind the question Interviewers rarely care whether you can recite two definitions. They are checking whether you know **where the joining knowledge is written down**, because that single fact predicts everything else: who reviews a cross-service change, what breaks when a service renames a field, and what a migration costs. Hold one example in mind throughout: an airline seat-map graph. A seat-inventory service owns `SeatMap` and `Seat` for a flight. A separate fares service owns what each seat costs. A client wants `Seat.price`. ## What a stitched gateway actually contains In stitching, both services are already GraphQL servers. The gateway does three things. First it **acquires the remote schemas** — usually by introspecting each service at start-up, or by reading SDL files checked into the gateway's own repository. Note the consequence immediately: the gateway now holds a *copy* of each service's type system, and that copy has an age. Second it **merges the type systems**, resolving conflicts by configuration. The fares service also has a type called `Seat` — a fare row, not a physical seat — so the gateway renames one of them, or filters it out of the merged schema entirely. Third, and most importantly, it holds **delegation rules**. A rule says: the field `Seat.price` on the merged `Seat` type is not resolved by either service directly; to resolve it, take the already-resolved parent `Seat`, read its `flightNumber` and `seatNumber`, call the fares service's `seatPrices` operation with those values, and graft the result into the response at that path. Every one of those three things is written in a file the gateway team owns. The inventory service does not mention fares. The fares service does not mention seat maps. That is genuinely the appeal — you can stitch two services you did not write and cannot change, including third-party ones. ## What a composed graph contains instead Composition moves the same knowledge into the services. The fares team writes, in its own schema, in its own repository: this graph's `Seat` is identified by flight number and seat number, and I contribute a `price` field to it. A composition step reads every service's published schema and merges the declarations into one graph, which a router then serves. No central mapping file exists. When the fares team wants to contribute another field, it edits its own schema and deploys on its own cadence. When a new service joins, it declares its own participation. ## The consequence, stated as a test you can apply Ask: *a client wants a new field that crosses a service boundary — whose pull request is it?* - Stitched: the gateway's. However well-intentioned the gateway team is, cross-team work now queues behind one team's review, and that queue is the thing that grows with the organisation. - Composed: the owning team's. The gateway team's job shrinks to running the router and keeping composition healthy. This is why the choice is usually described as an organisational one rather than a technical one. Both approaches produce one endpoint and one schema for the client; the client cannot tell them apart from the outside. ## Specified, or merely conventional? Be precise here, because it is a standard follow-up. **The GraphQL specification says nothing about combining schemas at all.** It defines one type system, one document language, and one execution algorithm over a single schema. Stitching is therefore a library technique — different implementations spell the configuration differently, and there is no standard for it. Composition is standardised, but not by GraphQL: the Apollo Federation specification defines the directives a service uses to declare its contribution and the rules by which those declarations merge. That is a separate document layered on top of GraphQL. One asymmetry follows directly and often trips candidates up. A stitched gateway can rename, hide, wrap or otherwise transform a remote schema before merging it, because it is just configuration in one process. The composition specification defines no gateway-side rename: two services declaring a type with the same name are declaring the *same type*, and a conflict is fixed in the owning service's schema or by the two teams agreeing on one definition. Any tool that offers a transform on the composed path is offering something the specification does not. ## Why the distinction outlives the technique Stitching is the older approach and much less common in new systems, so it is tempting to file it under history. Interviewers still ask because plenty of production graphs are stitched, and because the underlying axis — central configuration versus distributed declaration — recurs everywhere. If you can name where the join lives and who edits it, you can answer the migration and the ownership questions that follow without having memorised anything else.

  • Do the services behind a stitched gateway have to know they are stitched?
    No, and that is the whole appeal. They are ordinary GraphQL servers; the gateway introspects or reads their schemas and does the merging on its own. It is why you can stitch a service you do not own or cannot modify. Composition requires the opposite — a service joins a composed graph only by declaring its own participation in its own schema.
  • Is schema stitching defined by any specification?
    No. The GraphQL specification defines a single schema, document language and execution algorithm, and says nothing about merging schemas. Stitching is a library technique, so its configuration format and transform capabilities differ between implementations. Composition is standardised, but by a separate document — the Apollo Federation specification — layered on top of GraphQL rather than by GraphQL itself.
  • Two services both define a type named Seat. Where is that collision resolved under each approach?
    Under stitching, in the gateway configuration: rename one, or filter it out of the merged schema. Under composition there is no gateway-side rename — two services declaring the same type name are declaring the same type, so composition either merges them if the declarations agree or fails. The fix belongs in the owning service's schema, or in the two teams agreeing on one definition.

Stitching is a switchboard operator's private crib sheet listing which extension answers which request; composition is every department printing its own extension on its own door.

saying these in an interview costs you the question

  • Says stitching and composition are the same technique
  • Claims the GraphQL specification defines schema merging
  • Thinks stitched services must be federation-aware
  • Assumes a stitched gateway needs no configuration
  • Believes composition can rename a service's types centrally
  • Cannot say who edits the join in each approach

context