API Versioning and Backward Compatibility: Contracts That Do Not Break Clients
URL/header versioning strategies, safe schema changes, and deprecation policy for public and internal product APIs.
Ali Mortazavi
Founder, Paradise Code
Compatibility is a product feature, not a tech detail
Every removed field or changed meaning breaks someone you cannot see: an old mobile app, a customer script, a partner integration. Versioning is a time-bound promise about change. Without that promise, feature speed trades away trust in the API.
First decide whether the API is public or internal. Internal APIs still need versions, but deprecation cycles can be shorter.
Where the version lives: path, header, or media type
Path versions (`/v1/...`) are explicit and easy for gateways and logs. Headers look cleaner in URIs but complicate discovery and caching. For most B2B and mobile products, path versioning is the clearest contract.
Reserve major versions for true breaks. Additive changes should not mint v2, or you get version explosion instead of discipline.
Safe changes vs breaking changes
Safe usually means: new optional fields, new endpoints, new enums that unknown clients ignore. Breaking means: removing fields, changing types, changing default meaning, making a formerly optional field required.
For renames, run a dual period: old and new fields together, then deprecation warnings, then removal in a major version.
Testable contracts and consumer-driven checks
Validate OpenAPI/Protobuf contracts in CI. Compatibility tests before merge prevent silent breaks. For multi-client teams, consumer-driven contracts pay off early.
Keep real response examples in docs—not only schemas. Clients copy examples; stale examples become distributed bugs.
Deprecation policy with dates and metrics
Deprecation without a date and without traffic metrics on the old version is theater. Announce a sunset date, monitor usage, and talk to client owners.
For mobile, accept store reality: users do not update. Sometimes you must keep an old version longer or feature-flag capability server-side.
Internal service and event versions
The same principles apply to messages and gRPC: do not delete fields, keep a compatibility mode, and tolerate unknown consumers.
An anti-corruption layer at boundaries lets internal models evolve without shaking the external contract.
Frequently asked questions
Does every UI change need a new API version?
No. Only contract-breaking changes. New features usually add optional fields or endpoints.
How many versions should we keep alive?
As few as possible—usually N and N-1. More explodes test and security cost unless you have contractual commitments.
Does GraphQL remove the need for versioning?
No; it changes the shape. Field deprecation and tolerance for old clients remain necessary.
Insights
Need these ideas implemented in your product?
Paradise Code supports you from consult to full delivery.