URL versioning vs header versioning
URL versioning embeds the API version in the URI path (/v1/users, /v2/users) or query string (?version=2). Header versioning communicates the desired version through an HTTP header - typically Accept: application/vnd.api+json;version=2 or a custom X-API-Version: 2 header. Both approaches are valid; the choice depends on trade-offs between discoverability, cacheability, and client complexity.
Why it matters in practice
Use URL versioning for public REST APIs unless you control every client and cache layer. The version lives in the URI, so it is visible in a browser, works with every HTTP client out of the box, and CDNs cache it correctly because the URL uniquely identifies the resource version. Header versioning keeps URLs clean and enables content negotiation, but it costs you: clients must set a custom header, shared links lose their version, and most CDNs cache by URL alone - so every version collapses into one cache entry unless you configure Vary. That last gap is the one that bites in production.
Common mistakes
- •Using header versioning for public APIs that are cached by CDNs - most CDNs cache by URL and ignore request headers, meaning all header-versioned requests hit the same cache entry regardless of version.
- •Not including the version in error responses for URL-versioned APIs - a 400 from /v1/users should identify itself as a v1 error in the response body.