Skip to main content

Composition failures — and the ones that pass silently

Composition errors that block your deploy are annoying. The compositions that succeed when they shouldn't are the ones that page you at 2am.

The loud ones (good, actually)

Hard composition failures — key mismatches, conflicting field types, invalid @requires — are your supergraph's type system working. Treat them like compiler errors, and get them in CI, not at deploy:

  • Every subgraph PR runs rover subgraph check (or equivalent) against the live supergraph state, not just its own schema.
  • Schema publishing is serialized. Two teams publishing conflicting changes "simultaneously" is a race you will eventually lose.

The silent ones

1. Shared value types drifting

Value types (plain types, enums, inputs defined in multiple subgraphs) compose by intersection/union rules that most engineers never read. Two subgraphs defining enum Currency with different members can compose — and a value that's valid in one subgraph is a runtime error when it flows through the other.

Fix: value types live in one place. Publish them as a shared contract package, or promote them to an owned entity. Never hand-copy.

2. Nullability weakening at composition

A field non-null in the owning subgraph but nullable in a contributor composes to the weaker promise. Clients see String where the owner guaranteed String! — codegen changes, and nobody decided that.

Fix: diff the composed supergraph SDL on every change, not just subgraph SDLs. The supergraph diff is the only truth about what clients experience.

3. @requires / @provides staleness

@provides is a performance promise ("I can resolve this without the owner"). When the underlying denormalized data stops being synced, composition still passes and queries still work — they just silently return stale data on one query path and fresh on another. Users see two different prices depending on which page they came from. This one is brutal to debug because it's plan-dependent.

Fix: treat every @provides as a cache with an invalidation story. If you can't articulate the sync mechanism, delete the directive and eat the extra hop.

Our composition checklist

  • Subgraph checks run against live supergraph state in CI
  • Composed supergraph SDL is diffed and reviewed, not just subgraph SDLs
  • Value types have exactly one source of truth
  • Every @provides documents its data-sync mechanism
  • Publishing is serialized; rollback of a single subgraph schema is tested