API versioning is one of those decisions that seems trivial — "just add /v2/" — until you have 50 clients on v1, 30 on v2, and a breaking change you need to roll out. The versioning strategy you choose affects every client integration, every SDK, and every internal team that depends on your API. This guide compares every major API versioning approach and helps you pick the least painful one.

API Versioning Strategies Compared

StrategyExampleProsConsBest For
URI Path/api/v2/usersMost visible, easy to test, easy to route, cache-friendlyURL changes; "v2" in URL forever; URL pollutionPublic APIs, REST APIs, external consumers
Accept Header (Content Negotiation)Accept: application/vnd.api+json;version=2Clean URLs, no URL versioning, REST purist-friendlyHarder to test (curl -H), harder to cache (CDN), invisibleInternal APIs, REST purists, when URL cleanliness matters
Query Parameter/api/users?version=2Easy default (no version = latest), simple to testEasy to forget, cache key complexity, pollutes parametersSimple APIs, internal tools, when path versioning is blocked
Custom HeaderX-API-Version: 2026-05-01Clean URLs, date-based (intuitive), easy to deprecateInvisible, hard to discover, hard to test, CDN issuesStripe-style date-based versioning, API gateways
Hostname / Subdomainv2.api.example.comComplete isolation, can run separate servicesDNS management, SSL certificates, infrastructure complexityMajor breaking changes, completely different implementations

Date-Based vs Semantic Versioning

ApproachExampleBest ForPioneered By
Date-Based (Calendar Versioning)2026-05-01APIs that evolve continuously with many small changesStripe, Twilio, AWS
Semantic (Major.Minor)v1, v2, v3APIs with clear, infrequent major breaking changesGitHub, most REST APIs
Rolling (No Version)No version identifierInternal APIs, GraphQL (deprecation instead of versioning)GraphQL, internal services

Stripe's Versioning Model (The Gold Standard)

# Stripe's approach: date-based versioning via custom header
# Stripe-Version: 2026-05-01

# Key principles:
# 1. Every API request is pinned to a specific version date
# 2. New features are added without breaking existing code
# 3. Breaking changes: old behavior is maintained for old versions
# 4. Upgrading is explicit: change the date, test, deploy
# 5. Old versions are supported for a long time (years)

# Why this works:
# - No URL changes ever
# - Clients control when they upgrade
# - Backward compatibility is the API's responsibility, not the client's
# - Can ship changes daily without breaking anyone

How to Deprecate an API Version Without Making Enemies

StepWhat to DoTimeline
1. AnnounceEmail all users of the old version, add deprecation header (Sunset, Deprecation)6-12 months before shutdown
2. MonitorTrack who is still on old version, reach out personally to high-usage clientsOngoing
3. WarnAdd deprecation warnings in API responses, documentation banners3-6 months before shutdown
4. Rate LimitSlow down old version responses (add 100ms latency, then 500ms)1-3 months before shutdown
5. Shut DownReturn 410 Gone with clear error message + upgrade linkAfter announced date

Bottom line: For public REST APIs, URI path versioning (/v2/) is the most practical — it is visible, easy to test, and works with all HTTP tooling. For developer-focused APIs, date-based versioning (Stripe model) is more elegant but requires more infrastructure. The key is not the format — it is maintaining backward compatibility and giving clients 6-12 months to migrate when you do break things. See also: REST API Best Practices and API Design Patterns.