skip to content

questions

4

What does a GraphQL schema check compare in CI, and what verdicts does it report?

level: juniorimportance: must knowfreq 56%

answer

  1. nothing in the spec protects a schema
  2. two schemas, not two files
  3. structural comparison, never textual
  4. three verdicts, not two
  5. the middle class is type-legal but risky

basics

~20 s

A schema check diffs the schema your branch would publish against the schema currently published, taken from a registry, and classifies every edit — commonly safe, dangerous or breaking. It is a tooling practice, not part of the GraphQL specification.

solid answer

~50 s

A schema check is a CI step that diffs the schema your branch would publish against the schema currently published for the environment you are deploying to — the baseline, normally held in a schema registry. The comparison is **structural**, over the type system, not textual, so reordering fields or reformatting the SDL produces no findings. Every individual edit gets a class. The widely used taxonomy is three-way: **safe** (no existing valid operation can be affected), **breaking** (a document that was valid becomes invalid, or a declared guarantee is withdrawn), and **dangerous** (type-legal, but consumer code can still mishandle the result — adding a value to an enum a client switches over is the classic case). A gate then applies policy to that list. None of this comes from the GraphQL specification: the language has no version negotiation, and a server will serve whatever schema you hand it.

code

graphql · 8 lines
graphql
enum CompartmentSize { SMALL MEDIUM LARGE }

type Compartment {
  id: ID!
  size: CompartmentSize!
  sizeCode: String @deprecated(reason: "Use size")
  bank: LockerBank!
}

go deeper

for a junior

Know the shape: two schemas go in — what the branch would publish and what is published now — and a classified list of edits comes out. Be able to say that GraphQL itself does none of this for you.

for a middle

Explain why the comparison is over the type system rather than the text, and why the taxonomy has a middle class at all. Give one concrete example of an edit that is type-legal yet still risky for a caller.

for a senior

Show where a green verdict is not enough: semantic changes leave the types identical, and a breaking verdict is a statement about possibility, not observed traffic. Say what evidence you would add before acting on either.

for a principal

Own what the check is for. It is a signal feeding a policy, not the policy itself, and a tool that reports formatting noise or blocks every removal outright will be routed around by the teams it was meant to protect.

## Why the check exists at all GraphQL ships one endpoint and one schema, and the specification gives you nothing to protect it. There is no version in the URL, no content negotiation, no compatibility rule a server enforces at start-up. If you delete a field, the server starts happily and every client that still selects it starts getting a **validation error on the whole request** — not a missing key, a rejected document. The only thing standing between an edit and that outcome is a process you build yourself. A schema check is that process, expressed as a CI step. So the first thing to say in an interview is the honest one: *schema checks are a tooling convention.* The specification does not define them, does not define a registry, and does not define the verdict names. Anyone who tells you "the spec classifies changes as breaking" is wrong. ## The two inputs **The proposed schema** — the schema this branch would publish if it merged. For a schema-first project that is the SDL after all files are combined; for a code-first project it is the executable schema the built server produces, printed back out. The check must take the *whole* resulting schema, not a `git diff` of one file, because an edit to a shared type or a code-generated fragment shows up nowhere in the file you touched. **The baseline** — the schema currently published for the environment the change is heading to, fetched from a schema registry. This is the half people get wrong; it is not the SDL on your main branch, and it is not the file you started from. ## Structural, not textual Both sides are parsed into type systems and walked: types, fields, arguments, input fields, enum values, union members, interface implementations, default values, and the nullability and list wrappers on each. Textual diffing would be useless — moving a type into another file, alphabetising fields, or rewrapping a description all produce large diffs and zero semantic change, and a gate that fires on those loses its audience within a week. ## The three verdicts Names vary between tools, but the common shape is three-way, and the interesting question is *why three rather than two*. * **Safe / non-breaking** — no currently valid operation can behave differently. Adding a field to an object type, adding an optional argument, adding a whole new type, editing a description. * **Breaking** — an operation that was valid becomes invalid, or a promise the schema made is withdrawn. Removing or renaming a field is the obvious member of this class. * **Dangerous** — the edit cannot invalidate any existing document, yet consumer code can still mishandle what comes back. Adding a value to an enum that appears in a response is the canonical example: every document stays valid, and a client that switches exhaustively over the members meets a value nobody handled. Adding a member to a union, adding a new implementation of an interface, and changing an argument's default value sit in the same class. A two-way split would force all of those into "safe", where nothing looks at them. The middle class exists so a human sees them. ## A worked diff Take a parcel-locker graph. The published baseline has `enum CompartmentSize { SMALL MEDIUM LARGE }`, a `Compartment.size: CompartmentSize!`, and a long-deprecated `Compartment.sizeCode: String`. The branch adds `OVERSIZE` to the enum, adds `Compartment.heightMm: Int`, and finally deletes `sizeCode`. The check reports three edits: `heightMm` **safe**, `OVERSIZE` **dangerous**, `sizeCode` **breaking**. That output is a list, not a decision — the *gate* is the policy layered on top, and the policy is where teams differ. And the dangerous line is not theoretical. The kiosk firmware on the locker banks switched exhaustively over `CompartmentSize` and fell into its default branch when it first saw `OVERSIZE`, refusing drop-offs at those banks until the fleet was patched. No document was invalid; nothing in the type system had been withdrawn. ## What the check cannot tell you **It reasons about possibility, not reality.** "Breaking" means *some* valid document could select the removed field — not that any client does. Recorded usage is the separate signal that turns "could" into "did" or "did not", and a gate without it either blocks every removal forever or waves them all through. **It sees types, not meaning.** Changing the units a field returns, the default ordering of a list, the encoding of an opaque cursor, or the validation a resolver applies to an argument leaves the type system byte-identical. A structural diff reports nothing, and a team that treats a green check as proof of compatibility has bought false confidence in exactly the cases it cannot see.

  • Why does the check take the whole built schema rather than a diff of the SDL files the branch touched?
    Because the published schema is the artefact clients see, and it is not the sum of the files in the diff. A shared interface edited elsewhere, a type produced by generation, or a code-first builder whose output changed will all move the published schema without appearing in the files you edited. Printing the whole built schema and comparing type systems is the only way the check sees what actually ships.
  • A branch reorders fields and rewrites several descriptions. What should the check report?
    Nothing worth failing on. Field order in the SDL carries no meaning for a caller — the response order follows the client's selection set — so a structural comparison sees no change. Description edits are usually reported as safe or filtered out entirely. A tool that raises findings for formatting trains people to skim its output, which is how a real breaking finding gets waved through.
  • The check comes back green. What kinds of incompatibility could still be in the change?
    Anything semantic. The same field returning distances in centimetres instead of millimetres, a list whose default ordering flipped, an opaque cursor whose encoding changed, a resolver that now rejects an argument value it used to accept, or a field that starts returning null where it never did before. The types are identical in every one of those, so no structural diff can see them; they need a changelog and a human.

It is a customs declaration for a shipment, not an inspection of the cargo: it checks that the manifest still matches what was declared last time, and cannot tell whether what is inside the box changed meaning.

saying these in an interview costs you the question

  • Says the GraphQL specification defines breaking-change classes
  • Compares the branch's SDL text instead of the built schema
  • Thinks a breaking verdict means a client is definitely affected
  • Treats a green check as proof nothing changed for callers
  • Believes the server refuses to start on a breaking edit
  • Collapses safe and dangerous into one non-breaking class

context

open as a page

A GraphQL schema check flags a field removal as breaking, yet recorded usage shows zero calls — what would convince you to ship it?

level: seniorimportance: must knowfreq 52%

basics

~20 s

The verdict says a document could select the field, not that one does. Usage evidence overrides it only if the observation window outlives your slowest-updating client, the traffic was not sampled, and the recording covers every path that reaches the schema.

open as a page

Where does a GraphQL schema check get its baseline, and why keep it in a registry?

level: middleimportance: should knowfreq 43%

basics

~20 s

The baseline is the schema currently published for the environment being deployed to. A registry stores that per environment, with a history of who published what and when, so CI can fetch a pinned, auditable answer instead of guessing from a branch.

open as a page

You own a GraphQL graph twelve teams publish to — what fails the schema-check gate, what only warns, and who may override?

level: principalimportance: should knowfreq 31%

basics

~20 s

Hard-fail only breaking edits with observed usage; require a named reviewer for the dangerous class and for breaking edits with credible zero-usage evidence; report nothing for safe additions. Make overrides possible but recorded, and treat the override rate as the gate's health metric.

open as a page