OpenAPI Versioning Strategies That Actually Scale
URL versioning, header versioning, or no versioning — the tradeoffs of each approach, and how your choice affects breaking change detection in SpecVault.
There are three mainstream ways to version an HTTP API. They all work, and they all have real costs. The right choice depends on who your consumers are, how often you break things, and how much backward compatibility you're willing to maintain in parallel.
Strategy 1: URL versioning (/v1/, /v2/)
The most common approach. You prefix all routes with a version number:
GET /v1/users/{id}
GET /v2/users/{id} # new version, different shape
Why teams choose it: It's explicit, cacheable, and visible in logs. Consumers know exactly which version they're calling. Old versions can be kept alive while new ones roll out.
The real cost: You end up maintaining N versions simultaneously. A bug fix has to be applied to both /v1 and /v2. Deprecation is a long, awkward process. Over time, old versions accumulate and teams are reluctant to remove them because consumers haven't upgraded.
With SpecVault: Register a separate service per version (Payments API v1, Payments API v2). Each has its own spec history and subscriber list. When you deprecate v1, you can see exactly which teams are still subscribed and notify them directly.
Strategy 2: Header versioning (Accept or custom header)
The version is specified in the request header rather than the URL:
GET /users/{id}
Accept: application/vnd.yourapi.v2+json
# or
X-API-Version: 2
Why teams choose it: Clean URLs. Feels more REST-pure. Some API gateway products support it natively.
The real cost: Much harder to test manually (you need tooling to set headers), harder to cache (proxies often ignore the Accept header for caching), and invisible in browser URL bars. Debugging "which version is this actually calling?" requires inspecting requests rather than reading the path.
With SpecVault: The spec you publish should represent the version you're tracking. If you publish one spec per header version, register a separate service for each. If your spec documents all versions together with discriminators, a single service works fine.
Strategy 3: No explicit versioning (continuous evolution)
Many internal and microservice APIs skip version numbers entirely. The contract is defined by the OpenAPI spec at a given point in time, and the commitment is: we will not break existing consumers without advance notice.
Why teams choose it: No parallel maintenance burden. No deprecation ceremonies. Simpler URLs. Works well when producer and consumer teams are in the same organisation and can coordinate changes.
The real cost: Breaking changes must be proactively communicated and coordinated. If you don't have a reliable way to detect and alert on them, consumers find out from production errors.
With SpecVault: This is the ideal use case. You register one service with one spec history. Every deploy publishes the current spec. Breaking changes are automatically detected and subscribers are alerted — the communication that makes unversioned APIs safe to use becomes automatic rather than manual.
When to bump a major version vs. add a new endpoint
A useful heuristic: if the change requires all existing consumers to update before they can function, that's a major version bump. If consumers can continue as-is and opt into the new behaviour when ready, add a new endpoint or field instead.
- Rename
/users/{id}to/accounts/{id}→ major version bump. Old URL breaks all callers. - Add a new
/users/{id}/preferencesendpoint → no bump needed. Existing callers are unaffected. - Change
created_atfrom ISO string to Unix timestamp → major version bump. All callers parsing the field break. - Add a new optional field
metadatato the response → no bump needed. Additive change.
The SpecVault perspective
SpecVault tracks changes between published spec versions, not between URL versions. The spec you publish represents the contract you're making. If you ship a major version and publish it as a new spec version in the same SpecVault service, the breaking changes are flagged and subscribers are alerted — which is exactly the right moment to reach them.
Whichever versioning strategy you use, the most important thing is consistency: pick one, apply it to all your services, and make sure your spec always reflects what's actually deployed.