OpenAPI Diff

An OpenAPI diff compares two versions of an API specification — the old contract and the new one — and reports what actually changed: endpoints removed, parameters that became required, fields whose type changed, enum values that vanished. Load or paste both specs below and this page classifies every change as breaking or non-breaking, so you can judge a vendor upgrade, or your own release, before it reaches production. Both files are parsed in this page, on your device — nothing is uploaded, which matters because specs describe internal endpoints you may not want on someone else’s server. New to the vocabulary? The companion article, breaking API changes, explained, defines every term used here.

Last updated:

Old spec (the contract clients use today)

Drop a file anywhere in this panel, pick one, or paste the text. Parsing happens locally; nothing leaves this device.

New spec (the candidate contract)

Drop a file anywhere in this panel, pick one, or paste the text. Parsing happens locally; nothing leaves this device.

What this differ checks — and what breaking actually means

A change is breaking when a client written correctly against the old spec can fail against the new one without changing a line of its own code. That definition drives every verdict on this page. Removing a path or an operation is breaking because existing calls have nowhere to go. Removing a response status — above all a 2xx — is breaking because client error handling was written around the old set. Adding a required parameter or a required request property is breaking because yesterday’s valid request is suddenly rejected. Changing a field’s type or format is breaking because parsers, validators and generated SDKs all key off the declared type. Removing an enum value is breaking because a client may still send it, or may receive data it can no longer interpret. Everything else — a new endpoint, an optional parameter, a new response field, a new enum value, a new status code — is reported as non-breaking: old clients keep working, even if they cannot use the new capability yet.

The comparison is structural, not textual. Both documents are normalised into the same model before anything is compared: every path and operation, its parameters keyed by name and location, its request body and each response reduced to a schema signature — a deterministic summary of types, formats, property names, required lists and enum values, built recursively with local $ref references resolved. That is why reordering keys, reformatting whitespace or rewriting every description produces an empty diff: none of those change the contract. It is also why a change buried three levels inside a referenced schema is still found — the signature expands the reference instead of comparing its name.

Two input shapes are accepted because the ecosystem publishes both: JSON is tried first, and when that fails the text is parsed as YAML, the format most hand-written OpenAPI documents use. Swagger 2.0 documents work too, including their in: body parameters and per-response schemas. There is deliberately no live fetching and no upload: paste the documents or drop the files, exactly as you would with a HAR capture, and the comparison runs when you press the button — not on every keystroke — so two large pasted specs stay responsive.

Use the result as a release gate, not as decoration. In a review, the breaking list is the agenda: each entry needs either a fix, a version bump, a deprecation window or a written decision that the break is intended and communicated. The non-breaking list is the changelog draft. Exporting the diff as JSON lets you archive that decision next to the release, and the copyable summary drops straight into a pull request — the same discipline you would apply to a webhook contract change, where a silently altered payload breaks every subscriber at once.

Honest limits, stated plainly. This differ compares the declared contract: it cannot see behaviour the spec does not declare, such as a field that keeps its type but changes its meaning, a new business rule, tighter rate limits, or an error message clients were (unwisely) parsing. It follows local references and compares schemas to a bounded depth, so pathological deeply-nested or mutually recursive schemas are summarised rather than expanded forever. And a diff with zero breaking changes is not a promise that an upgrade is safe — it is evidence that the documented contract held, which is exactly the evidence worth having before you deploy.

The classification table this page grades against

Removed path or operationBreaking. Calls to an endpoint that no longer exists fail outright; there is no compatible way to keep an old client working against it.
Removed response statusBreaking. Client retry, error-handling and monitoring logic is written against the declared status set; losing a 2xx is the most severe form.
Parameter became required / required field addedBreaking. Requests that were valid under the old spec are rejected by the new one, so every existing client must change before it can call the endpoint.
Type or format changedBreaking. Parsers, validators and generated SDKs are built from the declared type; integer to string (or int32 to int64) breaks strict clients even when the wire values look similar.
Property removed (request or response)Breaking. A request property clients send is ignored or rejected; a response property clients read becomes null or missing in their code.
Enum value removedBreaking. Clients may still send the removed value, or hold stored data using it. Enum values added are non-breaking and are reported separately.
AdditionsNon-breaking. New paths, operations, optional parameters, optional request properties, response properties, response statuses and enum values never invalidate a previously valid interaction.

Frequently asked questions

Are my spec files uploaded anywhere?

No. Both documents are parsed and compared in this page, on your device; comparing them makes no network request and nothing is stored. That is a deliberate rule: a spec is a map of your API — including internal and undocumented endpoints — and a tool that asked you to upload it in order to diff it would be collecting exactly the map you should keep private.

Which formats are accepted?

OpenAPI 3.x and Swagger 2.0, as JSON or YAML. The text is tried as JSON first and parsed as YAML when that fails. A document must carry a paths object to be recognised as a spec; anything else is reported as not-a-spec rather than silently producing an empty diff.

What counts as a breaking change here?

Anything that can make a correctly written old client fail: removed paths, operations or response statuses; parameters or request properties that became required; type or format changes; removed request or response properties; and removed enum values. Additions of anything optional are non-breaking. Description, title and formatting changes are ignored entirely — they are not contract changes.

How are referenced schemas handled?

Local references such as #/components/schemas/Pet (or #/definitions/Pet in Swagger 2.0) are resolved when signatures are built, so a change inside a shared schema is reported on every operation that uses it. Resolution is depth-bounded and cycle-safe, so recursive schemas cannot hang the comparison.

Can I archive or share a result?

Yes. The download button exports the full diff as JSON — summary counts plus every change with its severity, kind, path, method and structured detail — and the copy button produces a plain-text summary for a pull request or release note. Both are generated locally from the comparison you just ran.