Breaking Changes in APIs: How to Spot Them Before You Ship Them

by Eric Hanson, Backend Developer at Clean Systems Consulting

The change that looked safe

A team adds a new required field to a request body. It is a new feature — why would adding a field break anything? The field is required going forward, so of course existing requests without it should fail.

Except existing clients were not told about this field. Their requests still go out without it. Now they are getting 400 Bad Request on a payload that worked yesterday.

This is the category of breaking change that causes the most incidents: not the obviously destructive changes like removing endpoints or renaming fields, but the ones that look like additions or clarifications.

A taxonomy of breaking changes

Removals (obviously breaking):

  • Removing an endpoint
  • Removing a field from a response
  • Removing a supported HTTP method
  • Removing a valid enum value from input

Modifications (obviously breaking):

  • Renaming a field
  • Changing a field's data type (stringinteger)
  • Changing a field from optional to required
  • Narrowing the accepted value range (0–10000–100)

Additions that are breaking:

  • Adding a required field to a request
  • Adding a new mandatory query parameter
  • Making a previously ignored field now validated and rejected
  • Changing authentication requirements on a previously public endpoint

Behavioral changes (subtle):

  • Changing the sort order of a response array that clients depend on
  • Changing the format of a field value (2026-04-191745654400)
  • Changing which HTTP status code an error returns (400422)
  • Changing the semantics of a status field without renaming it

The behavioral category is the hardest to catch because nothing in the schema changed — only the runtime behavior did.

How to catch them before shipping

Schema diffing in CI. If you maintain an OpenAPI spec (and you should), run a diff tool on every pull request. Tools like oasdiff (open source, Go) or Optic can classify changes as breaking or non-breaking and block the merge if breaking changes appear on a non-versioned endpoint.

oasdiff breaking api-v1-main.yaml api-v1-branch.yaml --fail-on ERR

oasdiff distinguishes between ERR (breaking) and WARN (potentially breaking). Configure your CI to fail on ERR and require explicit review for WARN.

Consumer-driven contract tests. Tools like Pact let API consumers publish contracts — assertions about what they expect from each endpoint. The provider runs these contracts in CI. If a provider change breaks a consumer contract, the test fails before either party ships.

This is particularly effective for internal microservice APIs where you control both sides. For public APIs, it does not scale, but schema diffing covers most of the same ground.

Changelog review as a merge gate. For teams without CI tooling yet: require that any PR touching API response or request shapes includes an entry in a BREAKING_CHANGES.md file. The act of writing it forces the author to categorize the change explicitly. Code review catches the cases they missed.

The enum problem deserves special attention

Enums are a common source of unexpected breakage in both directions. Adding a new value to a response enum is usually safe — unless the client has a strict parser that rejects unknown values. Many typed languages and strict JSON parsers do exactly this:

type Status = 'active' | 'inactive' | 'suspended';
// If you add 'pending' on the server, this throws at runtime

The safe pattern is to document that clients must treat unknown enum values as unexpected but valid (i.e., handle them without crashing). Include this in your API contract documentation. Consider adding a warning to clients in the Sunset header pattern when you expand enums, even though expanding is not technically breaking by strict definition.

Removing an enum value from input is unambiguously breaking. Any client using that value now gets a validation error. This requires a version bump.

What to do with a breaking change you already need to make

If you have genuinely identified a breaking change that is necessary:

  1. Introduce the new behavior under a new version or feature flag
  2. Run both behaviors in parallel for a defined transition period
  3. Notify existing clients with the Deprecation and Sunset headers
  4. Monitor adoption of the new behavior before retiring the old one

The temptation is to treat internal or low-traffic APIs as exempt from this process. Resist it. The number of clients is not the metric that matters — the cost of an unannounced breaking change to even one client who depends on the old behavior is always higher than the cost of following the deprecation process.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

How to Write Rails Migrations Without Causing Downtime

Most Rails migration patterns that work fine in development will lock tables in production. Here is the mental model and specific techniques for schema changes that deploy safely on live databases.

Read more

Reducing API Complexity in Spring Boot — Consolidation, Query Parameters, and the Endpoints Worth Removing

Every endpoint is a permanent contract the moment a client integrates against it. API surface area grows easily and shrinks painfully. Here is how to keep it smaller from the start and how to reduce it when it has already grown.

Read more

How I Use Form Objects to Keep Rails Controllers Clean

Multi-model forms, complex validation logic, and params that don't map cleanly to database columns are where Rails' built-in form handling breaks down. Form objects fix all three without pulling in a framework.

Read more

Samsung, Kakao and Naver Hire Seoul's Best Backend Developers — Here Is What Startups Do

Seoul produces exceptional backend engineering talent. The companies with the longest recruiting pipelines and the largest comp budgets get there first.

Read more