API Versioning Strategies
Choose the right versioning approach to evolve your API while maintaining backward compatibility
Why Version Your API?
API versioning is essential for maintaining backward compatibility while allowing your API to evolve. Without proper versioning, changes to your API can break existing clients and integrations.
- Introduce breaking changes safely
- Support multiple API versions simultaneously
- Give clients time to migrate
- Document API evolution clearly
- Maintain stable contracts with consumers
Versioning Strategies
URL Path Versioning
The most common and straightforward approach. The version number is embedded directly in the URL path, making it immediately visible and easy to understand.
# Version in the URL path
GET /api/v1/users
GET /api/v1/users/123
POST /api/v1/orders
# Upgrading to a new version
GET /api/v2/users
GET /api/v2/users/123
POST /api/v2/orders
✅ Advantages
- Explicit and highly visible
- Easy to understand and implement
- Simple to route in web servers
- Easy to cache at CDN level
- Works with any HTTP client
- Simple to test in browser
❌ Disadvantages
- Technically violates REST (URL = resource)
- Clutters the URL structure
- Requires URL changes for version upgrades
- Can lead to URL proliferation
Query Parameter Versioning
The version is passed as a query parameter. This keeps the base URL clean and makes versioning optional—clients can omit the parameter to use the default version.
# Version as query parameter
GET /api/users?version=1
GET /api/users/123?version=1
GET /api/users?version=2
# Default version (when omitted)
GET /api/users # Uses latest or default version
# Alternative formats
GET /api/users?v=1
GET /api/users?api-version=2024-01-15
✅ Advantages
- Clean, resource-focused URLs
- Optional—can default to latest
- Easy backward compatibility
- Simple to add to existing APIs
- Flexible parameter naming
❌ Disadvantages
- Caching issues (query strings often not cached)
- Can be overlooked or forgotten
- Mixes versioning with other parameters
- Some proxies strip query parameters
Header Versioning
Version information is passed through HTTP headers, keeping URLs completely clean. This is considered more "RESTful" as URLs remain purely resource identifiers.
# Using Accept header with version parameter
GET /api/users
Accept: application/vnd.api+json;version=1
# Using custom version header
GET /api/users
X-API-Version: 1
# Alternative custom headers
GET /api/users
API-Version: 2024-01-15
# Microsoft style
GET /api/users
api-version: 2.0
✅ Advantages
- Clean, semantic URLs
- Follows REST principles
- Version metadata separate from resource
- Good for API-savvy consumers
- Can be set globally in HTTP clients
❌ Disadvantages
- Harder to test in browser
- Not visible in URL sharing
- Requires HTTP client configuration
- Can be accidentally omitted
- Some tools don't support custom headers easily
Content Negotiation (Media Type Versioning)
Uses custom media types in the Accept header to specify both the format and version. This is the most "RESTful" approach, treating different versions as different representations of the same resource.
# Vendor-specific media type with version
GET /api/users
Accept: application/vnd.company.api.v1+json
# Version 2 of the same resource
GET /api/users
Accept: application/vnd.company.api.v2+json
# Resource-specific versioning
GET /api/users
Accept: application/vnd.company.user.v1+json
# Date-based versioning
GET /api/users
Accept: application/vnd.company.api.2024-01+json
# Response includes Content-Type
HTTP/1.1 200 OK
Content-Type: application/vnd.company.api.v2+json
✅ Advantages
- Most RESTful approach
- URLs are pure resource identifiers
- Allows resource-level versioning
- Self-documenting media types
- Supports hypermedia patterns
❌ Disadvantages
- Complex to implement and test
- Not intuitive for newcomers
- Caching configuration more complex
- Limited tooling support
- Steeper learning curve
Deprecation Strategies
Properly deprecating API versions is crucial for a good developer experience. Give your consumers time and tools to migrate smoothly.
📢 1. Announce Deprecation
Communicate through documentation, changelog, emails, and the API itself. Give at least 6-12 months notice for major versions.
Link: <https://api.example.com/docs/migration>; rel="deprecation"
⏰ 2. Add Sunset Header
Use the standard Sunset HTTP header (RFC 8594) to indicate when an API version will be removed.
Link: <https://api.example.com/v2/users>; rel="successor-version"
⚠️ 3. Deprecation Warnings in Response
Include deprecation warnings in API responses to alert developers during development and testing.
{
"data": { ... },
"_warnings": [
{
"type": "deprecation",
"message": "API v1 is deprecated. Please migrate to v2.",
"sunset": "2024-06-01",
"migration_guide": "https://docs.example.com/migrate-v1-to-v2"
}
]
}
📚 4. Provide Migration Guides
Create comprehensive migration documentation with code examples, breaking changes list, and step-by-step upgrade instructions.
🔄 5. Parallel Running Period
Run both versions simultaneously for an extended period. Monitor usage of deprecated version and reach out to heavy users directly.
🚫 6. Graceful Shutdown
When the sunset date arrives, return 410 Gone with a helpful message pointing to the new version.
HTTP/1.1 410 Gone
Content-Type: application/json
{
"error": "api_version_retired",
"message": "API v1 has been retired as of 2024-06-01",
"upgrade_url": "https://api.example.com/v2/",
"documentation": "https://docs.example.com/v2/"
}
Comparison Table
Choose the right versioning strategy based on your API's needs and your consumers' expectations.
| Aspect | URL Path | Query Param | Header | Media Type |
|---|---|---|---|---|
| Visibility | ⭐⭐⭐ High | ⭐⭐ Medium | ⭐ Low | ⭐ Low |
| RESTfulness | ⭐ Low | ⭐⭐ Medium | ⭐⭐⭐ High | ⭐⭐⭐ High |
| Implementation | Easy | Easy | Medium | Complex |
| Caching | ⭐⭐⭐ Excellent | ⭐ Poor | ⭐⭐ Good | ⭐⭐ Good |
| Testing | Easy | Easy | Medium | Complex |
| Browser Support | ⭐⭐⭐ Native | ⭐⭐⭐ Native | ⭐ Limited | ⭐ Limited |
| Used By | Twitter, Stripe, Google | AWS, Google | Microsoft, GitHub | GitHub (also) |
When to Use Each Method
🔗 URL Path Versioning
Best for public APIs with diverse consumers, when discoverability matters, and when you want simple CDN caching. Most common choice for REST APIs.
❓ Query Parameters
Good for internal APIs, when backward compatibility is paramount, or when adding versioning to existing unversioned APIs.
📋 Header Versioning
Ideal for APIs consumed by technical teams with proper HTTP clients, when URL cleanliness is a priority, or enterprise integrations.
🤝 Media Type
Perfect for mature APIs following strict REST/HATEOAS principles, when different versions need different representations, or complex enterprise systems.
Versioning Best Practices
📝 Use Semantic Versioning
v1, v2, v3 (major versions only)
2024-01-15 (date-based)
v1.2.3 (too granular for APIs)
latest, stable (ambiguous)
🎯 Version at API Level
/api/v2/users
/api/v2/orders
/api/v1/users
/api/v2/orders (mixed versions)
📖 Document All Versions
Clear changelog between versions
No migration guides
⏰ Set Clear Timelines
6-month parallel operation
Sunset headers
Immediate shutdowns
No advance warning
🔄 Support N-1 Rule
e.g., v3 (current) + v2 (supported)
Only supporting latest
🏷️ Default Version Strategy
400 if version missing
Breaking changes without notice