Why version an API at all
Without versions, every breaking change lands on every client the moment it ships. Versioning turns a flag day into a migration window: old clients keep working, new clients get the new behavior, and the provider decides when the old version is retired.
URL path versioning
GET https://api.example.com/v2/invoices/inv_123The version is part of the path. It is the most common approach because it is obvious in logs, easy to route at a gateway, and trivial for clients to understand.
Trade-offs: versions tend to be coarse (v1, v2) and long-lived, so each major version bundles many changes together and becomes a large migration.
Header and media type versioning
GET /invoices/inv_123
Accept: application/vnd.example.v2+jsonThe URL stays stable and the version travels in a header, either a custom one or a vendor media type in Accept. This keeps resource URLs clean and lets one URL serve several representations.
Trade-offs: versions are invisible in a browser address bar and easy to forget in clients, caches must vary on the header, and debugging requires looking at headers rather than URLs.
Query string versioning
GET /invoices/inv_123?api-version=2024-06-01Simple to add and visible in URLs. It mixes versioning with filtering parameters, and some caches and tools treat query strings inconsistently.
Date-based versioning
Instead of v1 and v2, each change set gets a release date. Stripe pins every account to the API version that was current when it first made a request, and clients can override it per request. GitHub’s REST API uses a dated X-GitHub-Api-Version header.
X-GitHub-Api-Version: 2022-11-28Trade-offs: migrations are smaller and more frequent, but the provider maintains a compatibility layer that translates between many dated versions, and consumers face a steady stream of upgrades rather than occasional big ones.
Semantic versioning for SDKs
Client libraries usually follow semantic versioning: a major version signals a breaking change, a minor version adds functionality, a patch fixes bugs. SDK majors often track API versions, but not always, so consumers end up managing two version streams.
What versioning does not solve
Versioning buys time; it does not do the migration. Every consumer still has to find their call sites, change them, and convince themselves nothing else changed. Meanwhile the provider pays to run every old version until the last client moves. That ongoing cost is why providers eventually deprecate and sunset versions, and why automating the consumer side of a migration matters.
Frequently asked questions
What is the best way to version a REST API?
There is no single best way. URL path versioning is the most common and easiest to operate. Date-based versioning suits providers that ship frequent, small changes and can maintain a compatibility layer. Pick one strategy and apply it consistently.
Should every change get a new API version?
No. Additive, backward-compatible changes such as new endpoints or optional fields can ship without a new version. Reserve new versions for breaking changes.
How long should old API versions be supported?
Long enough for consumers to migrate safely. Many providers publish a minimum support window and announce retirements months in advance with Deprecation and Sunset headers.