OpenAPI Diff Checker
Compare two OpenAPI versions and see which changes actually break existing clients, with the reason for every verdict spelled out.
Before
YAMLAfter
YAMLVerdict
4 breaking changes. Existing clients will stop working — this needs a new major version or a migration path.
Changes
6 shown- breaking/pets/{petId}Path `/pets/{petId}` was removed.
Every call to it now 404s.
- breakingGET /petsParameter `apiVersion` (query) was added and is required.
Existing calls omit it and are now rejected.
- breakingGET /pets — Response 200`id` changed type from integer to string.
Any client that parses this value into a typed field stops working.
- breakingGET /pets — Response 200`tag` was removed.
A client reading this field now gets nothing.
- changedinfoAPI version changed from "1.0.0" to "2.0.0".
- addedGET /pets — Response 200`createdAt` was added.
Clients ignore fields they do not know about.
Both documents are parsed and compared in your browser. Local $refs are resolved; external ones are reported as not compared rather than assumed unchanged.
About the OpenAPI Diff Checker
Paste two versions of an OpenAPI document and this OpenAPI diff checker tells you which differences break existing clients. Every change is classified as breaking, a modification or an addition, and every classification comes with the reason it was made — so you can disagree with a verdict rather than having to trust it.
The definition it works from is a single sentence: a change is breaking if a client that worked against the old document can stop working against the new one without changing. Everything else follows from that, including the consequence people find counterintuitive — direction matters. Removing a property from a response is breaking, because a client reads it. Removing one from a request is not, because the client was sending it and the server now ignores it. Adding a required property is the exact mirror image.
A text diff cannot make that distinction. It will show you a hundred lines of reordered YAML and one deleted property with equal weight, and it has no idea which one ends someone's integration. This compares the two documents structurally, so reformatting, key reordering and YAML-to-JSON conversion produce no changes at all, and the twenty things that do matter are sorted with the breaking ones first.
Local $refs are resolved before comparison, so a schema behind a reference is compared properly rather than as a string. External references are not fetched, and are reported as not compared rather than being assumed unchanged.
- Breaking, modification and addition, with the reasoning attached to each verdict
- Direction-aware schema comparison — the same edit is breaking in a response and harmless in a request
- Structural, so formatting, key order and YAML/JSON conversion register as no change
- Paths, operations, parameters, request bodies, responses, schemas, security and servers
- operationId renames flagged as breaking, because generated SDKs name methods after them
- Enum values checked in both directions — narrowing a request breaks callers, widening a response breaks exhaustive switches
- Description and summary edits excluded by default, and available on a switch
- A copyable plain-text report for a pull request or a changelog
How to use it
- Paste the published version on the left and the version you are about to ship on the right. Either can be YAML or JSON.
- Read the verdict. If there are breaking changes, they are what a consumer will notice first.
- Use the filter buttons to look at one category at a time.
- Read the reason under any verdict you disagree with — the rule is stated, so you can decide whether it applies to your consumers.
- Copy the report into your pull request or changelog.
Real-world use cases
API product & platform teams
Review the breaking-change list before approving a version bump, using it as the source of truth for whether a release is a minor or a major under semantic versioning of the API itself.
Backend developers
Check a branch's spec against main before opening a pull request, catching an accidental breaking change — a property quietly made required, a status code removed — before a reviewer has to spot it by reading YAML.
Frontend & client developers
See exactly which fields changed shape between two API versions before regenerating a client, instead of discovering the mismatch as a runtime type error after the fact.
QA & API testers
Use the addition and modification list to scope what a regression pass actually needs to cover for a release, rather than re-testing the whole surface because 'the spec changed.'
DevOps & CI/CD engineers
Model a CI gate that fails a build on any breaking change, using the same verdicts and reasoning this tool shows, with an explicit override path for the releases where breaking is intended.
Examples
A new required parameter
- name: apiVersion in: query required: true
breaking — Parameter apiVersion (query) was added and is required. Existing calls omit it and are now rejected.
The same parameter without required: true is an addition and breaks nothing.
The same edit, two directions
remove the `tag` property
in a response → breaking: a client reading this field now gets nothing in a request → modification: the server ignores it now
This is the distinction the whole tool is built around, and the one a text diff cannot make.
A property type change
id: { type: integer } → id: { type: string }breaking — id changed type from integer to string.
Silent at the HTTP level and fatal in any typed client. It is the change most likely to ship unnoticed.
An enum value added to a response
enum: [active] → enum: [active, suspended]
changed — now also allows "suspended". A client with an exhaustive switch on this value will not handle the new one.
Not breaking at the protocol level, and breaking in a Rust or TypeScript client that matched exhaustively. Flagged with the reason so you can judge it.
Common errors
| Message | Cause | Fix |
|---|---|---|
| 422 Unprocessable Entity after a deploy | A request field became required, or a parameter changed from optional to required. | Both are reported as breaking. Accept the old shape for a deprecation period rather than switching in one release. |
| Cannot read properties of undefined in a client | A property was removed from a response schema, and the client dereferences it without checking. | Reported as breaking with the property path. Keep the field and mark it deprecated for a release before removing it. |
| A generated SDK will not compile after regenerating | An operationId was renamed, so the generated method name changed. | Reported as breaking. Generators name methods after operationId, so a rename is a breaking change in every SDK even when the HTTP interface is identical. |
| 401 Unauthorized on requests that used to work | A security requirement was added to an operation or to the whole document. | Reported as breaking. Roll it out by accepting both authenticated and unauthenticated calls first, then requiring auth. |
| The diff is full of changes but I only edited one line | Almost always the specification was reformatted or converted between YAML and JSON at the same time. | This tool compares structurally, so formatting alone produces no changes. If you see many, they are real — check whether a $ref was inlined, which changes the structure even when the meaning is the same. |
| was not compared below depth 8 | A very deeply nested schema hit the comparison depth limit. | Reported rather than passed over silently, so you know that part is unverified. Deeply recursive schemas usually need a manual read anyway. |
Frequently asked questions
›Are my specifications uploaded?
No. Both documents are parsed and compared in your browser. That is worth caring about here because you are typically diffing an unreleased version against a published one, and the unreleased half is the part you would least like to leak.
›What exactly counts as breaking?
A change is breaking if a client that worked against the old document can stop working against the new one without changing. That covers: removing a path, operation, response status or media type; adding a required parameter or request property; making something required that was optional; changing a type; removing a property from a response; removing an enum value a request could send; and adding a security requirement. Each verdict shows its reasoning, so you can decide whether it holds for your consumers.
›Why is removing a request property not breaking?
Because the client is the one sending it. If the server stops reading a field, a client that keeps sending it carries on working — the value is simply ignored. It becomes breaking only if the schema sets additionalProperties: false, which turns the extra field into a validation failure, so it is reported as a modification with that caveat rather than being ignored.
›Why is an operationId rename breaking when the HTTP interface is identical?
Because every OpenAPI code generator names its client method after operationId. Rename it and the next regeneration produces a differently named method, so consumers' code stops compiling even though nothing about the requests changed. It is the clearest case of a change that is invisible over the wire and breaks people anyway.
›Should I fail CI on breaking changes?
On the specification for a published API, yes — that is the most useful thing this classification is for. The workflow is to diff the merged specification against the last released one and fail the build when the breaking count is above zero, with an explicit override for the releases where breaking is intended. Copy the report into the pull request so reviewers see what was flagged.
›Does it follow external $refs?
No. Local #/... references are resolved and compared properly. An external reference would require fetching a file this page does not have, so each one is reported as not compared — you know precisely which parts were checked. Bundle both documents into single files first if you need everything covered.
›Why are description changes hidden by default?
Because in a real specification they are most of the diff and none of the risk. Documentation edits, typo fixes and reworded summaries would bury the handful of changes that actually affect consumers. The switch turns them on when you want a complete picture.
›Can it tell me if a change is breaking for a specific client, not just in general?
No — it reasons about the specification, not about any particular consumer's code. A change flagged as breaking might not affect a client that never reads the removed field, and a change flagged as a modification could still break a client that made an unusually strict assumption. Treat the verdicts as what the contract permits, and confirm impact against your actual consumers for anything on the edge.
Last updated