The most common source of customer-breaking SDK releases is a spec change that looked benign. "I just added a field" — and the new field is required. "I just renamed an enum value" — and three SDKs published with the old value. The fix is detection: a diff between the previous and next OpenAPI spec, scored against a clear rule for what's breaking.
This post is the practical version of that rule, plus the tools that enforce it.
What's breaking, in plain rules
Breaking on the wire (server-side):
- Removing an endpoint.
- Removing a method on an existing endpoint.
- Renaming a path parameter.
- Adding a required parameter or required request-body field.
- Removing a response status code or response field that clients depend on.
- Tightening a schema constraint (max length down, integer min up, enum value removed).
- Changing the type of an existing field (
string→integer). - Changing auth scheme requirements.
Breaking the SDK (client-side):
- Anything from the server list, plus:
- Renaming an
operationId— changes the SDK method name. - Renaming a schema in
components/schemas— changes the SDK type name. - Changing parameter order in a way the generator surfaces positionally (most generators don't, but verify).
- Changing the discriminator value in a polymorphic union.
Not breaking:
- Adding a new endpoint.
- Adding a new optional parameter or optional request-body field.
- Adding a new response status code that didn't exist.
- Adding a new optional response field.
- Adding a new enum value (debatable — see below).
- Adding a new schema in
components/schemas.
The enum-value gotcha
Adding a new enum value to a response is technically additive, but it breaks any client that exhaustively switched on the enum. Most TypeScript and Python clients do.
Three positions, in order of caller-friendliness:
- Treat new enum values as breaking. Safest. Worst velocity.
- Treat them as additive but flag them prominently. Reasonable default — most SDKs emit unknown enum values as
stringrather than throwing. - Treat them as additive silently. Cheapest. Pays back in customer issues a year from now.
Pick one and document it in your versioning policy.
Tools that catch all of this
oasdiff
go install github.com/oasdiff/oasdiff@latest
oasdiff breaking ./prev.yaml ./next.yaml
The reference open-source tool. Reports breaking changes with line numbers. Supports OpenAPI 3.0 and 3.1. Configurable severity (you can promote enum additions to breaking if you want).
Wire it into CI by saving the last-shipped spec to a git tag and diffing every PR against it.
openapi-diff (OpenAPITools)
A different openapi-diff (https://github.com/OpenAPITools/openapi-diff). Works at the spec level only, lighter output, easier to skim in a PR comment. Good when you want a human-readable summary, not a CI gate.
Bloom's compatibility report
Bloom runs a diff every time a new spec is pushed and produces a report tied to the SDK output, not just the spec. The distinction matters:
- An OpenAPI diff says "this field changed."
- A compatibility report says "this field changed, and because of how the TypeScript SDK exposes it, customers calling
client.users.create()will see a TypeScript error on upgrade."
The report runs on every spec push during the 30-day free trial. No credit card required.
See SDK compatibility reports, explained for the longer write-up.
CI integration in three lines
The minimum viable setup:
# .github/workflows/openapi-diff.yml
on: [pull_request]
jobs:
diff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: oasdiff/oasdiff-action/breaking@v0.0.48
with:
base: origin/main:openapi.yaml
revision: openapi.yaml
fail-on: ERR
This fails the PR if oasdiff breaking reports anything at ERR level. Tune the threshold based on your team's appetite — WARN is a useful softer gate for early projects.
What to do when you have to break
Sometimes a breaking change is the right call. The pattern:
- Bump the major version on the affected SDK package.
- Ship a written migration guide alongside the release.
- Keep the previous major published and supported for 90 days minimum.
- Tag the previous spec version so customers can pin if they need time.
See REST API versioning best practices for the longer pattern (URL versioning vs header vs date-based).
Bottom line
Spec drift is silent and customer-breaking. A diff in CI plus a compatibility report before publishing catches the vast majority of issues that would otherwise reach customers. Both are cheap. Skip them and you ship the same regression twice a quarter for the rest of your API's life.
Try Bloom free for 30 days — every spec push runs the compatibility scanner and produces a written report against your last shipped SDK before any publish. Completely free for 30 days. No credit card required.