Versioning Strategies
When a change would break existing clients, you need a versioning strategy so old and new clients can coexist. There are three common places to put the version.
Breaking vs non-breaking
Section titled “Breaking vs non-breaking”First, decide whether you even need a new version. Non-breaking (additive) changes never require one:
- Adding a new endpoint or a new optional field.
- Adding a new optional query parameter.
- Adding a new value to an output-only enum (if clients are told to tolerate unknowns).
Breaking changes do require one: removing or renaming a field, changing a type, making an optional field required, or changing the meaning of a response.
Three strategies
Section titled “Three strategies”- URI versioning —
GET /v1/articles. Most visible and easiest to route and cache; the version is right there in the URL. Downside: the same resource lives at two URIs across versions. - Header versioning — a custom or standard header like
API-Version: 2. Keeps URIs clean, but the version is invisible in logs and harder to try in a browser. - Media-type versioning — negotiate via
Accept: application/vnd.example.article+json;version=2. The most RESTful (the version is part of the representation), but the most awkward to use.
GET /v1/articles # URI versioningGET /articles # header versioningAPI-Version: 2
GET /articles # media-type versioningAccept: application/vnd.example.article+json;version=2Choosing
Section titled “Choosing”For most teams, URI versioning wins on pragmatism: it is obvious, cache-friendly, and trivial to test. Whatever you choose, version the whole API at a coarse grain (v1, v2), not each endpoint independently — per-endpoint versions explode the support matrix.