Two Ways to Make Many Schemas Look Like One
Two Ways to Make Many Schemas Look Like One
Both approaches solve the same problem: several services expose GraphQL, and clients want one endpoint. They differ in when the merge happens and what each subgraph must agree to.
Stitching merges schemas inside the gateway process. At startup (or on demand) the gateway loads every source schema, builds a new executable schema whose resolvers delegate to the underlying services, and serves that. The merge is runtime machinery: the gateway can be handed a new source and re-stitched while it runs, and the sources need no shared conventions — a stitched field can resolve from a REST client, a SOAP call, or a database directly.
Federation merges schemas in CI. Each subgraph publishes SDL that follows federation rules (keys, shareability), composition produces a supergraph, and the gateway loads that artifact and plans against pre-computed ownership metadata. The merge is a build artifact: it changes only when a subgraph publishes, and every change is reviewable.
stitching federation
source schemas --(runtime)--> subgraph SDLs --(CI)--> supergraph
| |
v v
gateway builds a delegating gateway loads routing metadata,
schema, resolves by delegation compiles plans per operation shape
| |
+-------- one endpoint ----------->+
The practical consequence: with stitching, "what is the current schema?" is answered by the running process, and every source must be reachable at boot. With federation, the answer is a versioned artifact produced by a build, and a source that is down at deploy time is a composition input problem rather than a gateway boot failure.
Decision Criteria That Actually Separate Them
Decision Criteria That Actually Separate Them
Neither tool is the general answer; the estate decides. Four criteria separate them cleanly:
| Criterion | Favors stitching | Favors federation |
|---|---|---|
| Source types | heterogeneous: REST, SOAP, non-conformant GraphQL | every source is a GraphQL subgraph you control |
| Identity | no natural shared key across services | types carry an id or tuple that doubles as a key |
| Team model | one platform team maintains the gateway | many teams own slices and ship independently |
| Governance | permissive — you decide conventions in the gateway | enforced — composition rejects ownership mistakes |
Stitching wins on heterogeneous legacy estates. A third-party SaaS API, a legacy SOAP service, and a monolith you cannot touch can all be wrapped by a delegate with no schema rules imposed on them. It also wins when sources must appear or disappear at runtime — multi-tenant setups where each tenant's schema is different, or a gateway that aggregates APIs discovered after deploy. Federation cannot compose a schema it has not been given, and nothing it offers matters if half your data is not GraphQL.
Federation wins on team autonomy. Ownership rules are machine-checked: two teams cannot both silently resolve a field, keys make cross-service references explicit, and schema checks run against live traffic before merge. That governance is the product. The registry, versioned composition inputs, and standard plan tooling all follow from treating the supergraph as a build artifact. Teams already sharing entity-style types — every domain object has an id, services reference each other by id — are most of the way to federation already.
The cost asymmetry matters too. Stitching concentrates complexity in one gateway codebase you own end to end; federation distributes it across many subgraphs and a composition pipeline you must operate. If one platform team is maintaining a stitched gateway, that complexity lives in one place. If forty engineers would each have to understand a hand-written delegation layer, federation's machine-enforced rules are cheaper than the review burden.
Migrating, and Where Stitching Still Wins
Migrating, and Where Stitching Still Wins
You rarely switch wholesale. The safe path is incremental:
- Inventory the estate. Which services already expose GraphQL? Which have ids usable as keys? Which are third-party and untouchable?
- Federate the conforming slice. Convert the services that already share entity conventions into subgraphs, compose them, and serve that slice from the gateway.
- Wrap the rest. A non-conforming service can sit behind a small adapter subgraph: it exposes federation SDL with keys and resolves fields by calling the legacy API. Federation never has to touch the original system.
- Keep the stitched surface until traffic moves. The old stitched endpoint and the new supergraph can run side by side behind the same domain, with clients cut over per operation.
Two things break more often than expected: resolver conventions (subgraphs must implement entity resolution, not just field resolvers) and authorization (rules that lived in one stitched gateway must be re-expressed per subgraph or at the gateway as directives).
Where stitching remains the right answer. Dynamic sources — per-tenant schemas, APIs registered after deploy, third-party GraphQL you do not control — have no build-time composition input, so federation's central advantage never applies. Non-GraphQL data sources need a delegate that federation does not provide. And a single platform team that already owns its gateway gets more flexibility from re-stitching than from adding registry infrastructure.
The honest summary for an interview: federation is what you adopt when your problem is many teams changing one graph, and stitching is what you keep when your problem is many unlike sources behind one endpoint. See federation architecture for the ownership model federation enforces, and subgraph composition for what the build step actually checks.
Practice Problems
Two candidates arrive at architecture review. For each, pick stitching or federation, give three criteria that decide it, and sketch the gateway-side wiring you would start with. Be prepared to defend the choice against the opposite recommendation.
Example:
Input: Estate A: 4 teams, 6 internal GraphQL services, every type has an id, schema registry already in CI, field ownership disputes are common. Estate B: 1 gateway, sources = one third-party GraphQL (no keys), a SOAP billing service, one internal REST API, schemas discovered per tenant at runtime.
Output: A → federation: shared identity (@key), many owners, composition enforces ownership and checks run against live traffic. Start: publish the 6 subgraph SDLs, compose in CI, gateway loads supergraph. B → stitching: no build-time input exists (runtime-discovered schemas) and two sources are not GraphQL, so @key cannot be declared. Start: gateway loads source schemas at runtime, delegates per field, re-stitch on tenant discovery.
Estate A’s pain is governance across owners, which composition turns into CI failures; its types already carry identity, so @key costs nothing. Estate B has no static input set — federation composes schemas it has been given, and runtime-discovered per-tenant schemas are given after deploy, so only runtime merging can serve them.
Optimal Solution — O(S) over S sources time, O(1) space
Evaluate three axes in order: (1) is there a static, complete set of GraphQL schemas? (2) do types carry identity usable as keys? (3) how many independent owners must change the graph? Only if all three favor it does federation win.
function choose(est) {
const staticInputs = est.sources.every(s => s.kind === 'graphql' && s.discovery === 'deploy');
const hasKeys = est.sources.every(s => s.keyFields && s.keyFields.length > 0);
const manyOwners = est.ownerCount > 3;
if (staticInputs && hasKeys && manyOwners) return 'federation';
if (!staticInputs || !hasKeys) return 'stitching';
return 'federation'; // one owner, static inputs: federation still, but a modular monolith is cheaper
} Edge Cases:
- Mixed estate: federate the conforming services and wrap the odd source in an adapter subgraph before defaulting to stitching
- One team with static inputs — federation works but buys little; a modular monolith may be cheaper
- Third-party GraphQL with keys: still stitching unless you accept maintaining an adapter subgraph indefinitely
Quiz
1. When does a stitching gateway merge its source schemas?
2. Which estate is the clearest case for stitching over federation?
3. What does a team get from federation that a permissive stitched gateway does not enforce?
4. How do you migrate a stitched gateway to federation without a big-bang cutover?
Flashcards
Question
Stitching merge point
Click to reveal answer
Answer
Runtime, inside the gateway: source schemas become a delegating executable schema, re-stitchable while running.
Question
Federation merge point
Click to reveal answer
Answer
Build time, in CI: published subgraph SDLs compose into a versioned supergraph artifact.
Question
Pick stitching when
Click to reveal answer
Answer
Sources are heterogeneous (REST/SOAP/third-party), identity is not shared, or sources must appear at runtime.
Question
Pick federation when
Click to reveal answer
Answer
Many teams own slices, types already carry usable keys, and you want composition-enforced ownership plus schema checks.
Question
Adapter subgraph
Click to reveal answer
Answer
A thin federation subgraph wrapping a legacy system, exposing keys and resolving via the old API — the migration bridge.
Revision Notes
Key Takeaways
- 1. The real difference is merge time: runtime delegation versus a build-time artifact
- 2. Stitching suits unlike sources; federation suits many teams sharing entity conventions
- 3. Migrate incrementally: federate conforming services first, wrap the rest, cut over per operation
Interview Tips
- • Answer comparisons with criteria, not adjectives: source heterogeneity, identity model, team topology, governance enforcement
- • Name one concrete migration move (adapter subgraph) instead of saying "gradually"
Cheat Sheet
| Stitching | Federation | |
|---|---|---|
| Merge | runtime, in gateway | build time, in CI |
| Sources | any (REST/SOAP/GraphQL) | GraphQL subgraphs with keys |
| Identity | ad hoc per delegate | @key field sets, agreed |
| Governance | conventions you enforce by review | composition failures in CI |
| Add source | re-stitch at runtime | publish + compose |
| Best for | unlike or dynamic sources | many teams, one graph |
Migration ladder: inventory → federate conforming services → adapter subgraphs for legacy → side-by-side endpoints → cut over per operation.
Keep stitching when there is no build-time input: per-tenant schemas, third-party GraphQL, non-GraphQL sources.