API versioning

On this page 7

API versioning is the practice of labeling and managing changes to an application programming interface so that existing clients keep working while the interface evolves. In the design of APIs, a version identifies a specific contract: the endpoints, operations, fields, data types, error formats and behaviors that a client can rely on.

Versioning matters because an API is a promise to code its provider does not control. Mobile apps, partner integrations and internal services may run old releases for months or years, so the provider needs a disciplined way to introduce breaking changes without breaking callers.

Breaking and non-breaking API changes

The core question of API versioning is whether a change is backward compatible. A non-breaking change lets every existing client continue unchanged; a breaking change forces at least some clients to update their code. Only breaking changes require a new major version, provided clients follow the tolerant reader principle and ignore fields they do not recognize.

ChangeUsually breakingReason
Add an optional request fieldNoOld clients simply omit it
Add a response fieldNo, for tolerant clientsUnknown fields are ignored
Add a new endpointNoExisting calls are unaffected
Remove or rename a fieldYesClients reading it fail or get null
Make an optional field requiredYesOld requests become invalid
Change a field type or formatYesParsing and validation break
Add a value to an enum in a responseOftenStrict clients reject unknown values
Change default behavior or error codesYesClient logic depends on them
Typical API changes and their compatibility

Subtle changes cause most incidents. Tightening validation, reordering a list that clients assumed was sorted, or changing rate limits can break integrations even though the schema looks the same. A useful rule is that observable behavior is part of the contract, not only the documented fields.

Where the version is expressed

Web APIs signal the version in one of several places in the request, and each choice has consequences for routing, caching and discoverability. The URI path approach, such as /v2/orders, is the most common for public REST APIs because it is visible and easy to route at an API gateway.

SchemeExampleMain trade-off
URI path/v2/ordersVery visible, but a version is not a resource
Query parameter/orders?version=2Easy to add, easy to forget or cache badly
Custom headerApi-Version: 2Clean URLs, less visible in logs and browsers
Media typeAccept: application/vnd.shop.v2+jsonFine-grained, but complex for clients
Date-based versionApi-Version: 2026-03-01Many small steps, requires careful tooling
Hostnamev2.api.example.comAllows separate deployment, adds DNS overhead
Common API versioning schemes

Header and media-type schemes keep resource URLs stable, which purists prefer, but they require caches and CDNs to vary responses by header. Date-based versioning pins each client account to the version current when it first integrated and applies a chain of small transformations to translate between versions, an approach that suits providers with frequent changes and many customers.

Version numbers and semantic versioning

Most public APIs expose only a major version to clients, because minor and patch changes are backward compatible by definition and need no client action. Internally, teams often track the full Semantic Versioning form, MAJOR.MINOR.PATCH, in the OpenAPI description and in SDK releases, so that documentation and generated code reflect every additive change.

Other API styles handle versioning differently. GraphQL usually avoids explicit versions: fields are added freely and old ones are marked with the @deprecated directive, then removed after monitoring shows no usage. gRPC with Protocol Buffers relies on field numbers that must never be reused, so adding fields is safe and breaking changes go into a new package name such as orders.v2.

API styleUsual approachKey rule
REST APIMajor version in path or headerBump major only for breaking changes
GraphQLContinuous evolution of one schemaDeprecate fields before removing them
gRPCVersion in the protobuf package nameNever reuse or renumber field tags
Webhook payloadsVersion per subscription or event typeLet consumers opt in to new formats
Versioning conventions by API style

Deprecation and the version lifecycle

A versioning policy is only credible with a defined deprecation and sunset process. A deprecated version still works but is no longer recommended; at its sunset date it stops responding or returns an error. Public providers commonly give six to twenty-four months between deprecation and removal, depending on how hard client updates are, and mobile apps usually need the longer end.

  • Announce deprecation in documentation, changelogs and directly to registered developers.
  • Signal it in responses with the Deprecation and Sunset HTTP headers so clients can detect it automatically.
  • Measure traffic per version and per client before choosing a removal date.
  • Run brownouts, short planned outages of the old version, to reveal forgotten integrations before the final shutdown.

Running many versions in parallel has a real cost: each live version must be tested, secured and monitored. Many teams therefore limit support to two concurrent major versions and implement old versions as thin adapters over the current code rather than as separate copies.

Common mistakes in API versioning

The most frequent error is versioning too often, which fragments the client base, or too late, after a breaking change has already shipped silently. Others include using one version number for unrelated resources, so a single change forces every client to migrate, and failing to version error formats and webhook payloads, which clients parse as carefully as normal responses.

API-first design reduces the need for breaking changes: when the contract is reviewed before implementation, naming and structure problems are caught while they are still cheap to fix. Designing responses with extensible objects instead of bare arrays or scalars also leaves room to add data later without a new version.

Understanding it simply

An API is like a printed form that two companies agree to exchange. If one company suddenly moves the boxes around, the other company’s software fills in the wrong places. API versioning means printing a new edition of the form and labeling it clearly, while still accepting the old edition for a while.

That way, everyone can switch to the new edition at their own pace, and nothing stops working overnight.

Applied in practice

A payments provider offers a REST API under /v1. Its charge object stores the amount as a decimal string such as “19.99”, which causes rounding bugs in several client languages. The team decides to represent amounts as integer minor units, so 19.99 becomes 1999, which is a breaking change. They publish /v2/charges with the new format, update the OpenAPI document and release new SDK versions the same day.

The /v1 endpoints keep working through an adapter that converts values. Responses from /v1 now carry Deprecation and Sunset headers with a date eighteen months away. Dashboards show which merchants still call /v1, and the team contacts the largest ones directly. Two short brownouts reveal a forgotten reporting script at one merchant. When the sunset date arrives, less than one percent of traffic remains on the old version, and its removal passes without a customer outage.