S SCHEMA.BIZ

Last updated:

Breaking Change Detector

Paste two versions of a JSON Schema or OpenAPI spec to detect breaking changes, warnings, and safe modifications. Get remediation suggestions and generate release changelogs.

Previous Version
New Version

What this tool does

The most dangerous schema changes are the ones that pass every test you have. Your tests use the new schema, your handlers use the new schema, every locally observable thing uses the new schema, but your deployed clients are still on yesterday's contract. The Breaking Change Detector compares two versions of a JSON Schema or OpenAPI document and categorizes every difference into three buckets: changes that break existing clients (require a major version), changes that are safe for additive evolution (minor version), and warnings that probably will not break anything but deserve a second look.

Each diff entry comes with a precise location (which property in which schema in which operation), a one-line explanation of why the categorization landed where it did, and a remediation hint where a safer alternative exists. The result is the kind of artifact a producer team can take to a consumer team without ambiguity: here is exactly what changed, here is what each change means for you, here is the version bump it implies. Everything runs in the browser; you can paste internal contracts without exposing them to a third-party service.

When to use the Breaking Change Detector

Reviewing a pull request that touches an API schema. A diff in YAML is hard to translate into "is this safe to release?" Drop the previous and proposed schemas into the detector and the verdict appears in seconds. Use the categorized output as the basis for the PR's compatibility section.

Cutting a release and writing the changelog. The detector's markdown output is structured for direct paste into release notes. The "Breaking" and "Added" sections give consumers a precise map of what they need to do to upgrade.

Auditing a vendor SDK upgrade. The vendor's release notes claim "minor changes." Run the diff against their old and new OpenAPI specs and you can confirm or refute the claim before scheduling the upgrade. A vendor that ships breaking changes under a minor version bump is a vendor whose changelog you have to verify.

Deciding what version bump to ship. The detector's classification maps directly to semantic versioning: any breaking change forces a major bump; any non-breaking addition is a minor; warnings-only is typically a patch. Use the output as the input to your release decision instead of debating it in a Slack thread.

Walkthrough with a real example

Paste this previous version of a Product schema on the left:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["id", "name", "price"],
  "properties": {
    "id":          { "type": "string" },
    "name":        { "type": "string", "minLength": 1, "maxLength": 200 },
    "price":       { "type": "number", "minimum": 0 },
    "description": { "type": "string" },
    "status": {
      "type": "string",
      "enum": ["draft", "active", "discontinued", "out_of_stock"]
    }
  }
}

And this proposed next version on the right:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "required": ["id", "title", "price", "currency"],
  "properties": {
    "id":           { "type": "string" },
    "title":        { "type": "string", "minLength": 3, "maxLength": 120 },
    "price":        { "type": "number", "minimum": 0, "maximum": 100000 },
    "currency":     { "type": "string", "enum": ["USD", "EUR", "GBP"] },
    "description":  { "type": "string", "maxLength": 5000 },
    "status": {
      "type": "string",
      "enum": ["draft", "active", "archived"]
    }
  }
}

The detector reports several diffs grouped by severity. Three changes are classified as breaking. The name property has been renamed to title — from a consumer's perspective, the old field has disappeared and a new one has appeared, which means every consumer reading the response will get an undefined value where they used to get a string. The currency property has been added to the required array, and existing clients sending the previous shape (no currency field) will be rejected at validation. The status enum has dropped two values (discontinued and out_of_stock) and added one (archived); any consumer that was sending one of the removed values will be rejected, and any consumer that hardcodes a switch statement over the enum will silently miss the new value.

Two more changes are classified as warnings. The name/title field has tightened its minLength from 1 to 3 and its maxLength from 200 to 120; this rejects payloads that previously validated, but only at the edges of the previous range. The price field has gained a maximum of 100000 where there was none before; a consumer sending a price above that bound will now be rejected, but in practice this is unlikely to affect callers. The remaining changes are non-breaking: the currency property addition is breaking only because of the required-list change above; the description field's new maxLength on a previously unbounded string is a warning rather than a breaking change because clients almost never send 5000-character descriptions.

The detector's remediation hints suggest the safer release path: keep name as a deprecated alias for title for at least one major version; let currency default to USD on the server side rather than requiring it; and keep the removed enum values as accepted-but-discouraged for one cycle. Implementing the hints turns a major version bump with a forced consumer migration into a minor bump with a deprecation timeline.

API evolution concepts you should know

Backward versus forward compatibility. A change is backward compatible if old consumers continue to work against the new producer; forward compatible if new consumers continue to work against the old producer. Most evolution work focuses on backward compatibility because consumer rollouts lag producer releases. Forward compatibility matters when consumers are pushed updates faster than producers (the inverse of most enterprise environments).

The producer/consumer asymmetry. Adding a required field is breaking for consumers (they have to send something new) but invisible from the producer's tests. Removing an optional field is breaking for consumers (the data they expected is gone) but harmless from the producer's side. The detector classifies from the consumer's perspective because that is where breakage actually shows up.

Semantic versioning for APIs. SemVer's MAJOR.MINOR.PATCH maps to "breaking changes," "additive changes," and "internal fixes." Bump MAJOR when any consumer must change to keep working. Bump MINOR when consumers can adopt new features at their own pace. Bump PATCH for behavior fixes that do not change the schema. Strict adherence to SemVer means consumers can pin to a major version and trust upgrades within it.

Deprecation lifecycles. The pattern that scales: announce the deprecation at version N (typically with a deprecation header on responses or a flag in the schema); add the replacement at version N+0.1; ship both side-by-side for a window measured in months for public APIs; remove the deprecated form only at version N+1.0. Skipping any step here generates angry support tickets.

Additive-only evolution. The discipline of accepting that you will only add to an API, never modify or remove. New optional fields, new enum values, new endpoints — these can be released indefinitely without a major bump. The cost is accumulating cruft; the benefit is consumers that never break. Many high-stability APIs (Stripe, AWS) maintain the discipline for a decade or more.

How schema changes propagate. A change to a shared component schema affects every operation that references it. The detector resolves $ref pointers and reports the change at every call site, not just at the definition, so the blast radius of a single component edit is visible. This is the easiest source of accidental breakage in a large OpenAPI spec.

Common mistakes

Adding a new required field without a deprecation cycle. Even if the new field has a sensible default on the server, a strict consumer that round-trips the response back to the producer will lose the field's value. Add as optional first, give consumers a release to pick it up, then promote to required.

Renaming fields without keeping the old name as an alias. Renames are the highest-frequency cause of avoidable breakage. Either keep the old name as a deprecated alias for one major version, or do the rename behind a feature flag that consumers can opt into.

Removing enum values that consumers actively send. Enums are the API contract's vocabulary. Removing a value rejects every payload that used it. Mark removed values as deprecated for a release cycle and only delete them when traffic to them goes to zero.

Tightening constraints silently. Lowering a max, raising a min, or adding a stricter pattern rejects payloads that previously validated. Treat constraint tightening as breaking even if your tests still pass — somewhere out there is a producer-fixture file with the old bounds.

Assuming description changes are always safe. Most of the time they are. But documentation changes can affect autogenerated SDKs (some generators use descriptions in JSDoc), automated test suites that snapshot the spec, and API gateways that use descriptions for catalog metadata. The detector flags description changes as warnings rather than ignoring them.

FAQ

Does the detector work with full OpenAPI specs, or only with bare JSON Schemas?

Both. For OpenAPI 3.x specs it walks the paths, operations, parameters, request bodies, and response schemas as well as the components. Removed paths and methods are flagged as breaking, added ones as safe. Component schemas get the same per-property analysis as standalone JSON Schemas. The output groups changes by operation so the diff stays readable on large specs.

How does the detector think about GraphQL-style breaking changes?

The principles transfer cleanly. Removing a field is breaking; making a non-null field nullable is safe for consumers but breaking for producers; adding a non-null argument to an existing field is breaking. Convert your GraphQL schema to JSON Schema with the Schema Converter first, then run the diff — the categorization rules produce the same verdicts you would get from a GraphQL-aware tool.

Does it follow $ref pointers when comparing two schemas?

Internal $ref pointers are resolved before the comparison so you get a structural diff, not a textual one. If the target of a $ref changes, the diff reports the change at the call sites rather than at the definition. External pointers (across files) are treated as opaque — inline them before pasting if you need them analyzed.

Can I run this check automatically in CI?

The web tool is for interactive review. For CI use the open-source schemabiz-diff package, which uses the same detection rules and exits non-zero on breaking changes. A typical workflow checks out the previous schema from main, compares it against the version in the pull request, and blocks the merge until breaking changes are explicitly approved:

# .github/workflows/api-contract.yml
- name: Detect breaking changes in API schema
  run: |
    npx schemabiz-diff \
      --previous origin/main:openapi.yaml \
      --next openapi.yaml \
      --fail-on breaking
  if: github.event_name == 'pull_request'

Does the detector generate a release changelog?

Yes. The results panel includes a markdown changelog that groups changes into 'Breaking', 'Added', 'Changed', and 'Notes' sections, formatted for direct paste into release notes or a PR description. The wording is suitable for an external audience — it describes the impact on consumers rather than the diff at the schema level.

Related tools and guides

  • OpenAPI Editor — author and validate the spec before you cut a release; the editor's preview makes it easy to review the consumer-facing documentation alongside the changes the detector flags.
  • JSON Schema Validator — when a breaking change is reported, validate real payloads against both versions to see exactly which payloads stop working.
  • Schema Format Converter — when consumers consume the schema as TypeScript types or Zod validators, regenerate them after a release so the type changes propagate cleanly.
  • API Versioning Guide — covers when to choose URL-based, header-based, or query-parameter versioning, and the operational patterns for running multiple versions in parallel.
  • Complete Guide to JSON Schema — the underlying vocabulary the detector compares; understanding the keywords lets you anticipate which edits will be classified breaking.