API Designhigh

Backward Compatibility

A backward-compatible change allows existing clients to continue working without modification. Breaking changes require clients to update their integration.

Memory anchor

Backward compatibility = the headphone jack promise. You can add Bluetooth, add USB-C, add wireless — but the moment you remove the 3.5mm jack, a million old headphones become paperweights.

Expected depth

Safe (non-breaking) changes: adding optional request fields with defaults, adding response fields, adding new enum values (with caution), relaxing validation rules, adding new endpoints. Breaking changes: removing or renaming fields, changing field types, adding required request fields, changing HTTP methods or URL structure, tightening validation. For gRPC/Protobuf: never reuse field numbers, never change field types — both are wire-format breaking changes even if the schema compiles.

Deep — senior internals

Adding new enum values is technically a breaking change for strictly-typed clients (e.g., Java clients with exhaustive switch statements). The standard mitigation is to include an UNKNOWN/OTHER value in all enums and document that clients must handle unknown values gracefully. This is a protocol design pattern, not a technical fix. JSON Schema and OpenAPI contract drift — when the implementation diverges from the published spec — is the most common source of subtle breaking changes. Consumer-driven contract testing (Pact) catches this class of bug: each consumer has automated tests against the provider's actual behavior, not just its published spec.

🎤Interview-ready answer

I treat backward compatibility as a first-class engineering constraint, not an afterthought. Every API change goes through a checklist: is this change additive? Does it add required fields? Does it remove or rename anything? Does it change validation behavior? For Protobuf APIs, I run `buf breaking` in CI to catch wire-format breaking changes automatically. For REST APIs I run Pact contract tests against all registered consumer contracts in the provider's CI pipeline.

Common trap

Assuming that because you control all consumers you can ship breaking changes freely. In a microservices system, multiple services consume the same API, and they deploy independently. A breaking change in service A can silently break service B on its next deploy if you do not verify contracts.

Related concepts