graphql‑sdl‑diff
Paste two SDL schemas → a classified, PR‑ready changelog.
Your schemas never leave this device. The diff runs locally on a vendored graphql‑js.
What this tool does — and its honest limits
What it does. graphql-sdl-diff compares two GraphQL SDL strings and returns a
flat, classified changelog: every change graded breaking, dangerous or
safe, ready to paste into a pull request. It answers the question every schema change
raises — “will this break my clients?” — the same way a CI gate or a
schema-registry pre-flight check would, but instantly and locally. The parser and the core
breaking/dangerous taxonomy come from a pinned, vendored copy of the reference
graphql-js (16.11.0, MIT); this tool is the honest classification layer on top, not
a from-scratch GraphQL implementation.
The conservative rail. The classifier never emits a false
safe: anything it cannot prove backward-compatible is graded
dangerous and its line ends with the literal note
“this diff cannot prove it safe; review manually”, never quietly downgraded. The
Needs review counter beside it is a catch-all for a grade this page does not recognise;
the pinned graphql-js 16.11.0 taxonomy emits only breaking, dangerous and safe, so in practice
it stays at 0 and the review-manually cases sit in the dangerous bucket. Directive and custom-scalar
changes are always flagged rather than resolved — a directive’s runtime effect
(auth, rate limiting, formatting…) lives in your executor, outside the SDL, so no
type-only diff can judge it. One subtlety worth knowing: merely non-breaking relaxations
— an input field going String! → String, an
output field going String → String! — report as
no change, not safe; only added types, added output fields and noted
@deprecated changes earn the safe grade.
Honest limits. It diffs two complete SDL strings — it does not stitch
multiple .graphql files for you. Apollo Federation is a sharper edge than
“unsupported”: because the vendored graphql-js builds a real schema, SDL that
uses @key or @external without also declaring them is
rejected outright with Invalid oldSDL: Unknown directive "@key". and you
get no changelog at all. Feed it schema text that already carries its
directive @key(…) repeatable on OBJECT definitions — the composed
supergraph, or the SDL your subgraph returns from _service { sdl }
— and it diffs fine, grading a changed @key as dangerous
(DIRECTIVE_USAGE_CHANGED) because the federation semantics live in the gateway, not
the SDL. And like every schema differ, it detects type-system
breakage only: a field that keeps its type but changes its meaning is invisible here.