You ship v1 of your API. Customers integrate. Six months later, you need to rename a field, change a response shape, drop a deprecated endpoint. Every existing customer integration will break. They didn't sign up for a maintenance project on your schedule.
API versioning is the discipline of evolving your API without breaking existing consumers. Get the strategy right and you can ship breaking changes for years; get it wrong and you create permanent technical debt with thousands of integrations frozen on v1.
02
Where the version lives
Strategy
Example
Pros
Cons
URL path
/v1/users vs /v2/users
Visible, cacheable, easy to test in browser
Couples version to URL — REST purists hate it
Subdomain
v2.api.example.com
Different infra per version, easy traffic split
CORS pain, infra duplication
Header
Accept: application/vnd.api+json;version=2
"Cleanest" REST
Invisible, hard to debug, breaks browser testing
Query param
?api_version=2
Easy to test
Confused with business params
Date-based
Header Stripe-Version: 2023-10-16
Tiny granular versions; per-account pinning
Server must maintain N versions; complex internally
03
The Stripe model — date-based versioning
Stripe's approach is the gold standard for high-stakes APIs:
Every breaking change creates a new version dated to that release (e.g. 2023-10-16).
Each customer is pinned to whatever version their account was created at.
API requests can override via Stripe-Version header.
Stripe maintains all versions simultaneously — they have versions from 2011 still working.
Old versions implemented as transformation layers on top of the current internal model. New version is the default; older versions translate request/response on the wire.
Result: Stripe can ship breaking changes weekly. Old integrations work forever. Customers upgrade explicitly when they want new features. Cost: significant engineering complexity to keep N versions running.
04
Pragmatic guidelines
Prefer additive changes. Add fields, never remove. Add endpoints, don't repurpose existing. Old clients ignore new fields → no breakage. Most "breaking changes" can be reformulated as additive.
Reserve major versions for true breakage. Going from v1 → v2 should be rare (years apart). Most evolution stays within a major version.
Deprecate before removing. Add Deprecation + Sunset headers. Email customers. Provide a migration path. Give 6-12 months minimum.
Document on day one. OpenAPI / Swagger / API explorer. Consumers can't migrate without docs.
Test old versions in CI. If v1 still ships, tests for v1 still run. Otherwise it'll silently break.
The temptation to avoid
"We'll just version when needed." Translates to "we'll never version, we'll just break things and email people." Decide on the strategy day one. Cheaper to have unused versioning than to retrofit it.
05
Deep dive — handling deletes the additive way
You want to remove the nickname field from /users. Removing it would break old clients. Additive solution:
Stop populating nickname in new records. Field still exists in schema, returns null for new users.
Document the field as deprecated.
For 12 months, monitor: who is still calling expecting non-null? Email those clients.
After deprecation period: stop returning the field. Old clients see "missing key" — most JSON parsers handle gracefully. Hard breakers get a 12-month notice.
Same for renames: add display_name; populate both fields; deprecate nickname; eventually drop it. Two writes for the deprecation period; old clients keep working; new clients use the new name.
If a real breaking change is unavoidable: bump major version. Run both. Set a sunset date for the old major. Communicate. Repeat.
06
Real-world
Stripe
Date-based, per-account pinning
Every breaking change = new version dated. Versions kept indefinitely. Internal transformation layers handle old contracts.
GitHub REST API
URL versioning + media types
/v3/ path + Accept: application/vnd.github.v3+json for sub-version features. Now mostly pushing toward GraphQL.
Twilio
URL versioning
/2010-04-01/ in path. Each major version a new path. Maintained for years past launch.
AWS APIs
Date-based per service
Each AWS service uses an internal API version date. Backwards compatibility is maintained essentially forever — APIs from 2006 still work.
07
Used in problems
URL shortener APIs version via path (/v1/shorten) for clean separation. E-commerce APIs use URL + sub-versioning for minor field additions. Payment gateway uses Stripe-style date-based versioning for max compatibility. News feed mobile API versions independently from web.