API versioning seems simple until you have 5 clients consuming 3 versions simultaneously. Here’s how we design APIs that evolve gracefully without the complexity of maintaining multiple versions indefinitely.
The Real Problem
Versioning isn’t about supporting v1 and v2 forever. It’s about giving clients time to migrate while you continue improving the API. The goal: minimize the number of active versions and make migration as painless as possible.
Strategy 1: Additive Evolution (Our Default)
The best versioning is no versioning. Design APIs to evolve additively: add new fields as optional, add new endpoints alongside existing ones, and never remove or rename existing fields. Clients that don’t need new features simply ignore new fields.
This works for 80% of API changes. New features, additional data, and enhanced functionality can all be added without breaking existing clients. The key discipline: never change existing contracts.
Strategy 2: URL Versioning for Breaking Changes
When additive evolution isn’t possible (removing fields, changing data types, restructuring responses), use URL-based versioning: /api/v1/users → /api/v2/users. It’s explicit, cacheable, and easy to route in your infrastructure.
The v1 endpoint continues working unchanged. New clients use v2. Set a deprecation timeline: typically 6-12 months for v1 sunset, with sunset headers in responses to notify clients.
Strategy 3: Header-Based Versioning
For fine-grained versioning, use custom headers: Accept: application/vnd.myapi.v2+json. This keeps URLs clean and allows versioning at the content-type level. The downside: less visible in logs and harder to debug.
The Migration Toolkit
Deprecation headers: Include Sunset and Deprecation headers in responses for endpoints nearing end-of-life. Good clients will log warnings.
Migration guides: For every major version bump, publish a migration guide documenting every breaking change with before/after examples.
Compatibility shims: For internal clients, build thin adapter layers that translate between versions. This lets the frontend migrate gradually rather than in a single Big Bang.
Usage monitoring: Track which versions each client uses. When v1 usage drops below your threshold, schedule the sunset with confidence.
What We Recommend
Start with additive evolution as your default. When breaking changes are unavoidable, create a new URL version, maintain the old version for 6+ months, monitor usage, communicate deprecation timelines, and sunset when adoption allows. Never maintain more than 2 active versions simultaneously.
Need help with your project?
Our team specializes in building production-grade software. Explore our services:
Get engineering insights in your inbox
Production-tested approaches to AI, Laravel, React and more. No spam, unsubscribe anytime.


