Manage API evolution without breaking consumers. Covers versioning strategies, deprecation policies, backward compatibility, API changelogs, and consumer migration paths.
This reference explains how to manage API versions and their lifecycle in a way that preserves compatibility, enables upgrades, and avoids breaking existing clients. This applies when introducing changes to an API's interface, data structures, or behavior that might affect consumers who rely on it.
Versioned APIs often use the URL path to indicate which version is being requested:
GET /api/v1/users
GET /api/v2/users
GET /api/v3/users
When implementing this pattern, ensure that your routing logic properly handles the version prefix and routes to the correct handler or controller. The API server must validate that the version in the path matches the expected format and return a 404 for unknown versions.
Example implementation in Go:
func handleUserRequest(w http.ResponseWriter, r *http.Request) {
// Extract version from URL path
re := regexp.MustCompile(`/api/v(\d+)/users`)
matches := re.FindStringSubmatch(r.URL.Path)
if len(matches) < 2 {
http.Error(w, "Invalid API version", http.StatusBadRequest)
return
}
version := matches[1]
switch version {
case "1":
// Handle v1 logic
case "2":
// Handle v2 logic
default:
http.Error(w, "API version not supported", http.StatusNotFound)
}
}
Some APIs use the Accept or Content-Type headers to indicate version:
GET /api/users
Accept: application/vnd.myapp.v1+json
The server inspects the header and returns content in the appropriate format.
Example using curl:
curl -H "Accept: application/vnd.myapp.v1+json" https://api.example.com/users
Version can also be specified as a query parameter:
GET /api/users?version=2
When handling this, validate that the version parameter is present and valid. Return 400 for invalid values.
API endpoints may go through states: active → deprecated → retired. A deprecation schedule helps clients migrate.
Set a deprecation date in HTTP headers:
Deprecation: Wed, 31 Dec 2025 23:59:59 GMT
Sunset: Wed, 31 Dec 2026 23:59:59 GMT
You can also return a Warning header for immediate notice:
Warning: 299 "API version 1 deprecated, use v2" "2024-01-01"
When retiring an API version, maintain it for a sunset period to allow client-side migration. During this period:
410 Gone for requests against retired endpointsExample:
curl -v https://api.example.com/api/v1/users
> HTTP/2 410
> Deprecation: Wed, 31 Dec 2025 23:59:59 GMT
> Sunset: Wed, 31 Dec 2026 23:59:59 GMT
> Warning: 299 "API version 1 retired" "2024-01-01"
Use a standard response field to indicate the API version used for the response:
{
"version": "2.1",
"data": {
"users": [
{
"id": 1,
"name": "John Doe"
}
]
}
}
This allows clients to verify that they are receiving data compatible with their expectations.
When evolving the schema of an API response, ensure backward compatibility by:
deprecated flag or field in documentationExample of handling a missing required field in v1:
{
"version": "1.0",
"data": {
"users": [
{
"id": 1,
"name": "John Doe",
"email": null
}
]
}
}
Clients must be able to handle version mismatches gracefully:
curl -H "Accept: application/json;version=2.0" https://api.example.com/users
If the server doesn't support version 2.0, it should either:
Use Git tags or branches to manage different API versions:
git tag -a v2.0.0 -m "API version 2.0.0"
git checkout v2.0.0
Versioned documentation must be kept in sync with code changes. Each major release should have a corresponding branch or tag.
When deploying new versions, implement a gradual rollout:
Example of routing in a reverse proxy:
location /api/v1/ {
proxy_pass http://backend_v1;
}
location /api/v2/ {
proxy_pass http://backend_v2;
}
A common failure occurs when clients send requests to a newer endpoint without specifying the version, expecting it to default to the latest:
curl https://api.example.com/users
# Should return 400 or 406 if no version is specified
If not explicitly required, this can lead to inconsistent behavior between client and server expectations.
When a version is marked as deprecated but clients continue to use it past the sunset date, they may face:
An API might return a 404 for an endpoint that exists but is not available in the current version. The error response should include:
{
"error": {
"code": "VERSION_NOT_FOUND",
"message": "Version '3.0' not found for resource 'users'",
"version": "3.0"
}
}
Some endpoints may support versioning while others don't, leading to inconsistent client behavior. For example:
GET /api/v1/users/123 # Supports versioning
GET /api/stats # Does not support versioning
Clients might assume all endpoints follow the same pattern.
Not validating API version parameters in requests can cause unexpected behavior:
GET /api/v99/users # Returns default or latest version
GET /api/v1.5/users # May fail silently if not supported
Implement metrics to track how many requests are made against each API version:
# Total requests per version
api_requests_total{version="1.0"} 1234
api_requests_total{version="2.0"} 5678
This helps determine when to deprecate older versions.
Set up alerts to notify teams when deprecated versions are still in active use:
# Example alert query
api_requests_total{version="1.0"} > 1000 within 1d
Maintain a log of all version changes, including:
Example audit record:
{
"timestamp": "2024-01-01T10:00:00Z",
"action": "deprecate_version",
"version": "1.0",
"reason": "Breaking changes in v2.0",
"retirement_date": "2025-12-31"
}
Provide clear migration guides with code examples for transitioning between versions:
# Example command to update a client
curl -H "Accept: application/vnd.myapp.v2+json" https://api.example.com/users
Include example code for handling both old and new response formats.
Design APIs so that when a client uses an older version, they still get the most relevant data without breaking functionality:
curl -H "Accept: application/vnd.myapp.v1+json" https://api.example.com/users
# Should return all available fields from v1 format
Use tools like Postman or curl scripts to test that new versions don't break existing clients:
curl -H "Accept: application/vnd.myapp.v1+json" https://api.example.com/users | jq '.data.users'
Ensure that any change to an API returns the same response structure when possible.
This page was rewritten on 15 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.
We use cookies for analytics (Google Analytics) and advertising (Google AdSense) to improve your experience and support free content. Privacy Policy