API Backwards Compatibility
debt(d6/e6/b7/t7)
Closest to 'specialist tool catches it' (d5), +1 to d6. Tools like openapi-diff and spectral can detect breaking schema changes between API versions, but the detection_hints note automated=no, meaning these tools require deliberate setup and comparison of spec files. Many breaking changes (like field renames or type changes) only surface at runtime when clients start failing silently — clients receive null or unexpected types with no error. The tooling catches some cases but not all, pushing this above d5.
Closest to 'touches multiple files / significant refactor in one component' (e5), +1 to e6. The quick_fix says 'never remove or rename fields — add new fields instead; deprecate old ones with a Deprecation header and remove only after a migration window.' While adding a new field alongside an old one is relatively simple, implementing a proper versioning strategy, deprecation headers, migration windows, and maintaining dual fields across multiple endpoints touches many files and requires coordinated effort. If the API is already in production without versioning, retrofitting versioning is a cross-cutting concern approaching e7.
Closest to 'strong gravitational pull' (b7). API backwards compatibility is a persistent architectural concern that shapes every future API change. Once an API is public with external consumers (as noted in when_to_use), every new feature, every schema modification, every endpoint change must be evaluated against compatibility constraints. This applies across all web/api contexts and imposes an ongoing tax on development velocity — every change is shaped by this choice. It doesn't quite define the system's entire shape (b9), but it has strong gravitational pull on all API-related work.
Closest to 'serious trap — contradicts how a similar concept works elsewhere' (t7). The misconception is explicit: developers believe renaming a JSON field is a 'minor change' when it is actually a breaking change that silently breaks every client. This contradicts the internal development experience where renaming a variable or field is a routine, low-risk refactor. The common_mistakes reinforce this — adding required fields, changing nullability, removing fields — all feel like minor changes to an internal developer but are breaking changes for API consumers. The disconnect between internal code refactoring norms and API contract obligations is a serious cognitive trap.
Also Known As
TL;DR
Explanation
Safe (backwards-compatible) changes: adding optional fields, adding new endpoints, adding optional query parameters, adding new enum values (with caution — clients must handle unknown values). Breaking changes: removing fields, renaming fields, changing field types, changing response structure, removing endpoints, making optional fields required. Breaking changes require a new API version. Semantic versioning applies: v1 → v2 for breaking changes. Deprecation policy: announce → deprecate (with Deprecation header) → sunset date → remove.
Diagram
flowchart TD
subgraph Safe Changes - No Version Bump
A1[Add optional field to response]
A2[Add new endpoint]
A3[Add optional query param]
end
subgraph Breaking Changes - Requires v2
B1[Remove or rename field]
B2[Change field type]
B3[Make optional field required]
end
subgraph Deprecation Flow
CURR[Current field] -->|add new| BOTH[Both fields returned]
BOTH -->|Deprecation header + sunset date| DEP[Old field removed in v2]
end
style A1 fill:#238636,color:#fff
style A2 fill:#238636,color:#fff
style A3 fill:#238636,color:#fff
style B1 fill:#f85149,color:#fff
style B2 fill:#f85149,color:#fff
style B3 fill:#f85149,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Removing or renaming fields without a versioning strategy — all existing clients break silently.
- Adding required fields to a request body — existing clients don't send the field, their requests fail.
- Changing a field from nullable to non-nullable — clients handling null will fail if the type changes.
- No deprecation header or sunset date — clients have no warning before a field disappears.
Avoid When
- Internal APIs consumed only by your own team — strict backwards compatibility slows iteration unnecessarily.
- Early-stage APIs still being designed — lock the contract too early and you constrain good design decisions.
- Maintaining compatibility for zero consumers — prune unused versions rather than preserving them.
When To Use
- Public APIs with external consumers who cannot be forced to upgrade on your schedule.
- Mobile app APIs where old versions remain in the field for months or years.
- Any API covered by an SLA or partner contract that guarantees stability.
- After the API has been in production — any change to an existing field is a breaking change.
Code Examples
// v1 API response:
{ "user_name": "alice", "user_email": "alice@example.com" }
// 'Refactor' renames fields without versioning:
{ "name": "alice", "email": "alice@example.com" }
// All clients reading user_name now get undefined/null
// No errors thrown — silent breakage in production
// Additive transition — both names during migration:
{
"name": "alice", // New field
"user_name": "alice", // Kept for backwards compat (deprecated)
"email": "alice@example.com",
"user_email": "alice@example.com" // Kept (deprecated)
}
// Deprecation header:
// Deprecation: Sat, 01 Jan 2027 00:00:00 GMT
// Link: https://api.example.com/docs/migration; rel="deprecation"
// After sunset: bump to v2 which removes old fields