Best Practices

AI Rules for API Versioning

AI generates APIs with no versioning strategy — one breaking change affects every client. Rules for URL versioning, header versioning, deprecation policies, and backward-compatible evolution.

7 min read·January 26, 2025

One breaking change, every client breaks — no version, no deprecation, no migration path

URL versioning, backward-compatible evolution, Sunset headers, migration guides

AI Builds APIs That Cannot Evolve

AI generates APIs with: no version indicator (GET /api/users), breaking changes shipped directly (renamed fields, removed endpoints), no deprecation warnings (clients discover breakage in production), no migration path (old clients must update immediately or break), and no documentation of changes (changelog is the git log). Every client update becomes a coordinated deployment — ship the API and all clients simultaneously or something breaks.

Modern API versioning is: explicitly versioned (v1, v2 in URL or header), backward-compatible by default (additive changes only in the current version), deprecation-announced (Sunset header, deprecation notices months before removal), migration-documented (changelog + migration guide for each version bump), and multi-version supported (v1 and v2 run simultaneously during transition). AI generates none of these.

These rules cover: versioning strategies (URL path vs header), backward-compatible evolution, deprecation policies, sunset timelines, and client migration patterns.

Rule 1: URL Path Versioning as Default

The rule: 'Use URL path versioning as the default strategy: /api/v1/users, /api/v2/users. Path versioning is: visible (developers see the version in every request), cacheable (different URLs = different cache entries), simple to route (Express: app.use("/api/v1", v1Router); app.use("/api/v2", v2Router)), and debuggable (version is in logs, browser history, and curl commands). It is the most widely adopted pattern and the easiest to understand.'

For when to bump versions: 'Create a new version only for breaking changes: removing a field, renaming a field, changing a field type, removing an endpoint, or changing response structure. Additive changes (new optional fields, new endpoints) do not require a version bump — they are backward-compatible. If no client breaks, no new version is needed.'

AI generates: /api/users with no version. The first breaking change forces a choice: break all existing clients, or add versioning retroactively (and /api/users is now ambiguously v1 or unversioned). Starting with /api/v1 costs nothing and gives you a migration path from day one.

  • /api/v1/users — version in URL path, visible, cacheable, simple to route
  • Bump version only for breaking changes — additive changes stay in current version
  • Start with v1 from day one — adding versioning later is a breaking change itself
  • Route by version: app.use('/api/v1', v1Router) — clean separation of versions
  • Version in logs and monitoring — immediate visibility into which version clients use
💡 Start with v1, Day One

Adding versioning to an existing API is itself a breaking change — /api/users becomes ambiguously unversioned or v1. Starting with /api/v1/ costs zero effort and gives you a clean migration path when you eventually need v2.

Rule 2: Header Versioning for Advanced Use Cases

The rule: 'For APIs that need clean URLs or fine-grained version control, use Accept header versioning: Accept: application/vnd.rulesync.v2+json. The client specifies the desired version in the Accept header; the server responds with that version format. This keeps URLs version-free (/api/users for all versions) while allowing version negotiation.'

For default version behavior: 'When no version header is present, serve the latest stable version (not the latest experimental version). Document the default clearly. For backward compatibility, some APIs use a custom header: X-API-Version: 2 or Api-Version: 2026-03-01 (date-based versioning, as used by Stripe). Date-based versions are useful when the API evolves continuously rather than in discrete major versions.'

AI generates no version negotiation. The API serves one format — whatever was last deployed. Clients cannot request a specific version, cannot discover available versions, and cannot gracefully handle version changes. Header versioning adds one line of middleware and gives clients full control over which version they consume.

Rule 3: Backward-Compatible Evolution

The rule: 'Within a version, only make additive changes: new optional fields in responses (existing clients ignore them), new optional query parameters (existing clients do not send them), new endpoints (existing clients do not call them), new enum values in responses (existing clients handle unknowns). Never within a version: remove fields, rename fields, change types, make optional fields required, or change response structure.'

For the robustness principle: 'Be conservative in what you send, liberal in what you accept (Postel Law). Accept unknown fields in requests (ignore them gracefully). Send consistent field types (never null where a string is expected). Include empty arrays instead of omitting the field. Clients should ignore unknown response fields. This principle allows both API and clients to evolve independently.'

AI generates: a response with { name: string } today and { fullName: string } tomorrow — a breaking rename. Every client that reads name is broken. Backward-compatible approach: add fullName alongside name, deprecate name in documentation, remove name in the next major version. Two field names temporarily, zero broken clients.

⚠️ Rename = Breaking Change

Changing { name } to { fullName } breaks every client reading 'name'. Backward-compatible approach: add fullName alongside name, deprecate name in docs, remove it in the next major version. Two field names temporarily, zero broken clients.

Rule 4: Deprecation and Sunset Policy

The rule: 'Announce deprecation at least 6 months before removal. Use the Sunset HTTP header: Sunset: Sat, 01 Jan 2027 00:00:00 GMT. Use the Deprecation header: Deprecation: true. Include a Link header pointing to the migration guide: Link: <https://docs.example.com/migration/v1-to-v2>; rel="sunset". Clients that monitor these headers can plan their migration before the deadline.'

For the deprecation timeline: 'Phase 1 (month 0): announce v2, publish migration guide, add Sunset/Deprecation headers to v1. Phase 2 (month 3): send deprecation warnings in v1 response body or via webhook/email to known API key owners. Phase 3 (month 6): shut down v1, return 410 Gone with a migration link. This gives clients: 6 months of parallel operation, 3 months of active warnings, and a clear migration path at every stage.'

AI generates APIs with no deprecation strategy. Removing a field or endpoint is a surprise to every client. Monitoring the Sunset header is trivial (one middleware check). Sending it is trivial (one response header). The cost is near zero; the value is zero-surprise API evolution.

  • Sunset header — date when the version will be removed
  • Deprecation: true header — signals the version is deprecated
  • Link header with rel='sunset' — points to migration documentation
  • 6-month minimum deprecation period — announce, warn, then remove
  • 410 Gone after sunset — with Link to migration guide, not generic 404
ℹ️ Sunset Header = Zero Surprise

Sunset: Sat, 01 Jan 2027 00:00:00 GMT — one response header that tells every client exactly when this version disappears. Clients that check this header plan their migration. Clients that ignore it get 6 months of warnings before the 410 Gone.

Rule 5: Client Migration Strategies

The rule: 'Publish a migration guide for every major version bump: what changed, why it changed, how to update client code. Include: field mapping (old name to new name), endpoint mapping (old path to new path), request/response diff examples, and a code migration snippet for each supported SDK. Make migration mechanical, not intellectual — the developer should not have to understand why, just what to change.'

For gradual migration: 'Support both versions simultaneously during the deprecation period. Implement an API gateway or middleware that routes by version. Monitor version usage: when v1 traffic drops below a threshold (1% of requests), contact remaining v1 users directly before sunsetting. API versioning is a contract — breaking it without notice breaks trust.'

AI generates no migration support. Version bumps are: a new URL, a new response format, and silence. Clients discover breaking changes via 500 errors in production. Migration guides, changelogs, and Sunset headers transform version bumps from crises into planned transitions.

Complete API Versioning Rules Template

Consolidated rules for API versioning.

  • URL path versioning (/api/v1/) as default — visible, cacheable, simple
  • Header versioning (Accept: application/vnd.app.v2+json) for advanced needs
  • Start with v1 from day one — adding versioning later is itself a breaking change
  • Additive changes within a version — never remove, rename, or change field types
  • Robustness principle: ignore unknown fields, send consistent types
  • Sunset + Deprecation headers — 6 months before removal, with migration link
  • Migration guides for every version bump — field mapping, endpoint mapping, code snippets
  • Monitor version usage — contact remaining old-version users before sunset