Polyatic graphql-sdl-diff
All tools

graphql‑sdl‑diff

Paste two SDL schemas → a classified, PR‑ready changelog.

Old schema the baseline / currently deployed SDL
New schema the proposed / next SDL
— —
0 breaking 0 dangerous 0 review 0 safe
Changelog
Loading local diff engine…

Your schemas never leave this device. The diff runs locally on a vendored graphql‑js.

Use it in your own code

The classifier on this page is a published Node module built on the same pinned graphql‑js, so a pre-merge check can fail the build on a breaking schema change instead of a reviewer catching it.

npm install @verifyhash/graphql-sdl-diff

Three lines — a required argument added and a field renamed

const { diffSchemas } = require('@verifyhash/graphql-sdl-diff');
const changes = diffSchemas('type Query { user(id: ID!): User }\ntype User { id: ID! name: String }', 'type Query { user(id: ID!, org: ID!): User }\ntype User { id: ID! fullName: String }');
console.log(changes.map(c => `${c.severity.padEnd(9)} ${c.description}`).join('\n'));

prints

breaking  A required arg org on Query.user was added.
breaking  User.name was removed.
safe      User.fullName was added.

What the package does not include: this page — the two SDL panes, the severity filter and the Markdown changelog export. The diff engine is the same build: the core.js in the published 0.1.0 tarball is line-for-line the core.js inlined in this page’s browser bundle (compared 2026-09-22) and both vendor the same pinned graphql‑js 16.11.0, so the grades above are the grades your CI gets. The honest limits are the same too: it diffs two complete SDL strings, never stitches files or resolves Federation directives, and grades anything it cannot prove compatible as dangerous rather than safe.

@verifyhash/graphql-sdl-diff on npm · version 0.1.0 · MIT · also listed with our other libraries on Polyatic libs.

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.