skills/api-versioning/SKILL.md
Comprehensive guide to API versioning strategies, backward compatibility, deprecation, and lifecycle management. Use when user asks about "version API", "API compatibility", "breaking changes", "semantic versioning", "API evolution", "deprecation strategy", "backwards compatibility", "API migration", "version management", "sunset header", "API changelog", "schema versioning", "OpenAPI versioning", "GraphQL versioning", or mentions API lifecycle management, consumer migration, or version negotiation.
npx skillsauth add 1mangesh1/dev-skills-collection api-versioningInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Strategies for versioning APIs, managing backward compatibility, handling deprecation, and coordinating version lifecycles across consumers.
The version identifier is embedded directly in the URL path.
GET /api/v1/users
GET /api/v2/users
GET /api/v1/users/42/orders
Pros:
Cons:
When to use: Public APIs with external consumers. Stripe uses /v1/, Google Cloud uses /v1/ and /v2/.
Accept: application/vnd.mycompany.users.v2+json # content negotiation
X-API-Version: 2 # custom header
Pros:
Cons:
When to use: Internal APIs or where URL stability matters. GitHub uses Accept: application/vnd.github.v3+json.
GET /api/users?version=2
Pros:
Cons:
When to use: Internal tooling or debugging fallback. Rarely the best choice for production APIs.
Semver uses MAJOR.MINOR.PATCH:
For URL versioning, only MAJOR appears in the path (/v1/). Communicate MINOR/PATCH through changelogs or response headers (X-API-Version: 2.3.1).
Breaking changes (require new major version):
Non-breaking changes (safe within current version):
Gray area: Changing default values, adding required fields with defaults, changing rate limits, modifying field order in JSON.
Use the Sunset header (RFC 8594) with a Deprecation header and migration link:
Deprecation: true
Sunset: Sat, 01 Mar 2025 00:00:00 GMT
Link: <https://api.example.com/docs/migration-v3>; rel="successor-version"
deprecated: trueMonth 0: Announce deprecation. New version available.
Month 3: Notify all known consumers with migration guide.
Month 6: Warning headers on every old-version request.
Month 9: Reduce SLA to best-effort for deprecated version.
Month 12: Remove deprecated version. Return 410 Gone.
Public APIs with many external consumers may need 18-24 months.
Maintain at most two to three active major versions. Define clear states:
| State | Description | |------------|----------------------------------------------------------------------| | Preview | Available for testing, may change without notice | | Active | Fully supported, recommended for new integrations | | Deprecated | Functional but scheduled for removal, no new features | | Retired | Returns 410 Gone with pointer to successor |
Default version behavior when consumer omits version: fixed default (predictable but can strand users), latest stable (risky for unexpected breaks), or require explicit version (safest but adds friction).
Maintain structured, machine-readable changelogs:
{
"version": "2.3.0",
"date": "2025-01-15",
"changes": [
{ "type": "added", "endpoint": "GET /v2/users/{id}/preferences", "description": "Retrieve user preferences" },
{ "type": "deprecated", "endpoint": "GET /v2/users/{id}/settings", "description": "Use /preferences. Sunset: 2025-07-15" }
]
}
Categorize entries as: added, changed, deprecated, removed, fixed, security. Link to migration docs for breaking changes. Publish changelogs in documentation and as an API endpoint.
Additive changes only: The safest evolution strategy is to only add, never remove or rename:
// v1 response (original)
{ "name": "Alice", "email": "[email protected]" }
// v1 response after additive change (still v1, non-breaking)
{ "name": "Alice", "email": "[email protected]", "phone": "+1-555-0100" }
Optional fields with defaults: New request fields must be optional with sensible defaults so existing clients are unaffected. For example, a new role field defaults to "member" when omitted.
Response envelope stability: Keep the top-level response structure (data, meta, errors) consistent across all changes within a version. Consumers build deserialization logic around this structure.
Tolerant reader pattern: Encourage consumers to ignore unknown fields, avoid depending on field ordering, and handle missing optional fields gracefully. Document this expectation in your API guidelines.
API version changes often require schema changes. Strategies for coexisting versions:
Key rules:
Maintain separate spec files per major version (openapi-v1.yaml, openapi-v2.yaml). Mark deprecated operations:
paths:
/v1/users/{id}/settings:
get:
deprecated: true
summary: Get user settings (use /preferences instead)
x-sunset: "2025-07-15"
Use tools like oasdiff or openapi-diff in CI to detect breaking changes between spec versions automatically.
# v1 original
GET /api/v1/users/42 -> { "id": 42, "name": "Alice", "email": "[email protected]" }
# v1 additive (non-breaking)
GET /api/v1/users/42 -> { "id": 42, "name": "Alice", "email": "[email protected]", "created_at": "2024-01-15T10:00:00Z" }
# v2 restructured (breaking: name split)
GET /api/v2/users/42 -> { "id": 42, "first_name": "Alice", "last_name": "Smith", "email": "[email protected]" }
GraphQL avoids URL versioning. Evolve additively with built-in deprecation:
type User {
id: ID!
name: String! @deprecated(reason: "Use firstName and lastName")
firstName: String!
lastName: String!
email: String!
}
Monitor field usage analytics to determine when deprecated fields can be removed safely.
Tooling:
Communication:
Tracking migration progress:
Monitor the percentage of traffic still hitting deprecated versions. Use this data to:
tools
Parallel execution with xargs, GNU parallel, and batch processing patterns. Use when user mentions "xargs", "parallel", "batch processing", "run in parallel", "parallel execution", "process list of files", "bulk operations", "concurrent commands", "map over files", or running commands on multiple inputs.
development
WebSocket implementation for real-time bidirectional communication. Use when user mentions "websocket", "ws://", "wss://", "real-time", "live updates", "chat application", "socket.io", "Server-Sent Events", "SSE", "push notifications", "live data", "streaming data", "bidirectional communication", "websocket server", "reconnection", or building real-time features.
tools
Frontend bundler configuration for Webpack and Vite. Use when user mentions "webpack", "vite", "bundler", "vite config", "webpack config", "code splitting", "tree shaking", "hot module replacement", "HMR", "build optimization", "bundle size", "chunk splitting", "loader", "plugin", "esbuild", "rollup", "dev server", or configuring JavaScript build tools.
tools
VS Code configuration, extensions, keybindings, and workspace optimization. Use when user mentions "vscode", "vs code", "vscode settings", "vscode extensions", "keybindings", "code editor", "workspace settings", "settings.json", "launch.json", "tasks.json", "vscode snippets", "devcontainer", "remote development", or customizing their VS Code setup.