API Versioning
API versioning strategies for evolving APIs without breaking existing consumers
You are an expert in API versioning strategies for designing robust APIs. ## Key Points - Adding a new optional field to a response. - Adding a new endpoint. - Adding a new optional query parameter. - Removing or renaming a field. - Changing a field's type. - Altering error response structure. - Prefer URI path versioning for public APIs because it is the most explicit and easiest for consumers to understand. - Default to additive, non-breaking changes and only cut a new version when a breaking change is unavoidable. - Publish a deprecation policy with concrete sunset dates so consumers have time to migrate. - Versioning too aggressively, creating many versions that must all be maintained simultaneously. - Failing to communicate deprecation timelines, leaving consumers unaware until an old version is removed. ## Quick Example ``` GET /v1/users/42 GET /v2/users/42 ``` ```http GET /users/42 HTTP/1.1 Api-Version: 2 ```
skilldb get api-design-skills/API VersioningFull skill: 133 linesAPI Versioning — API Design
You are an expert in API versioning strategies for designing robust APIs.
Core Philosophy
Overview
API versioning allows you to introduce breaking changes while maintaining backward compatibility for existing clients. Choosing the right strategy depends on your consumer base, deployment model, and how frequently your API evolves.
Core Concepts
URI Path Versioning
The most visible and widely used approach. The version is embedded in the URL path.
GET /v1/users/42
GET /v2/users/42
Pros: simple to implement, easy to route, highly visible. Cons: proliferates route definitions, encourages large version jumps.
Header Versioning
The version travels in a custom request header, keeping URIs clean.
GET /users/42 HTTP/1.1
Api-Version: 2
Pros: clean URIs, easy to default to latest. Cons: harder to test in a browser, less discoverable.
Content Negotiation (Media Type) Versioning
Encode the version in the Accept header using a vendor media type.
GET /users/42 HTTP/1.1
Accept: application/vnd.myapi.v2+json
Pros: follows HTTP semantics precisely, supports per-resource versioning. Cons: complex to implement, unfamiliar to many developers.
Query Parameter Versioning
GET /users/42?version=2
Pros: easy to test, optional with a default. Cons: can be stripped by caches or proxies.
Implementation Patterns
Router-Level Version Dispatch
# FastAPI example with path versioning
from fastapi import APIRouter
v1 = APIRouter(prefix="/v1")
v2 = APIRouter(prefix="/v2")
@v1.get("/users/{user_id}")
def get_user_v1(user_id: int):
return {"id": user_id, "name": "Alice"}
@v2.get("/users/{user_id}")
def get_user_v2(user_id: int):
return {"id": user_id, "name": "Alice", "email": "alice@example.com"}
app.include_router(v1)
app.include_router(v2)
Additive Change Strategy
Minimize the need for new versions by making only additive, non-breaking changes.
Non-breaking changes (no new version needed):
- Adding a new optional field to a response.
- Adding a new endpoint.
- Adding a new optional query parameter.
Breaking changes (new version required):
- Removing or renaming a field.
- Changing a field's type.
- Altering error response structure.
Sunset Headers
Signal deprecation timelines using the Sunset HTTP header (RFC 8594).
HTTP/1.1 200 OK
Sunset: Sat, 01 Nov 2025 00:00:00 GMT
Deprecation: true
Link: </v3/users>; rel="successor-version"
Best Practices
- Prefer URI path versioning for public APIs because it is the most explicit and easiest for consumers to understand.
- Default to additive, non-breaking changes and only cut a new version when a breaking change is unavoidable.
- Publish a deprecation policy with concrete sunset dates so consumers have time to migrate.
Common Pitfalls
- Versioning too aggressively, creating many versions that must all be maintained simultaneously.
- Failing to communicate deprecation timelines, leaving consumers unaware until an old version is removed.
Anti-Patterns
Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.
Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.
Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add api-design-skills
Related Skills
API Authentication
API authentication patterns including OAuth 2.0, JWT, and API keys for securing HTTP APIs
API Documentation
OpenAPI and Swagger documentation practices for generating accurate, maintainable API references
API Error Handling
Error response design and HTTP status code conventions for consistent, actionable API error reporting
API Pagination
Pagination patterns including cursor-based, offset, and keyset pagination for efficient list endpoints
GRAPHQL Design
GraphQL schema design patterns for building flexible, efficient, and evolvable query APIs
REST Design
RESTful API design principles for building consistent, intuitive, and scalable HTTP APIs