# API versioning strategy exists

- **Pattern:** `ab-000365` (`api-design.versioning-evolution.versioning-strategy`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000365
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000365)

## Why it matters

An unversioned API has no mechanism to introduce breaking changes without breaking every existing consumer simultaneously. The first time a field is renamed, an endpoint is removed, or a response type changes, all integrators are affected with no warning or migration path. iso-25010:2011 compatibility.interoperability and maintainability.modifiability both require that the API surface area be stable across releases — and versioning is the mechanism that makes stability promises credible. Adding `/v1/` retroactively after you have external consumers is far more disruptive than doing it before launch.

## Severity rationale

Critical because an API with no versioning cannot introduce breaking changes without immediately breaking all consumers, making the API contract permanently fragile.

## Remediation

Add URL-based versioning to all endpoints now, before external consumers lock in on your paths:

```
// Before:
/api/users
/api/orders

// After:
/api/v1/users
/api/v1/orders
```

For GraphQL, version via `@deprecated` directives and a documented deprecation timeline rather than URL versioning. For gRPC, add package versioning to your `.proto` files: `package myapi.v1;`. If you already have consumers on unversioned paths, add a redirect layer from `/api/` to `/api/v1/` while you migrate client code.

## Detection

- **ID:** `versioning-strategy`
- **Severity:** `critical`
- **What to look for:** Check whether the API has a versioning strategy. Look for: URL-based versioning (`/api/v1/`, `/v2/`), header-based versioning (`Accept: application/vnd.api+json; version=2`, `API-Version: 2`), query parameter versioning (`?version=2`), or content negotiation. Also check: if a version indicator exists, is it applied consistently to ALL endpoints? For GraphQL: check for schema versioning via `@deprecated` directives or schema stitching. For gRPC: check for package versioning in `.proto` files (`package api.v1;`).
- **Pass criteria:** A versioning strategy is in place and documented -- either URL-based (most common), header-based, or framework-appropriate. Count all endpoints and verify that at least 100% include the version indicator consistently. Do not pass when versioning exists on some endpoints but not others.
- **Fail criteria:** No versioning of any kind. OR versioning exists but is inconsistently applied (some endpoints versioned, others not, e.g., `/api/v1/users` alongside `/api/orders`). OR multiple versioning approaches coexist without documentation.
- **Skip (N/A) when:** The API is internal-only with no external consumers AND the project is pre-launch with no published documentation. Signal: no public API docs, no SDK, no webhook endpoints, no third-party integrations.
- **Detail on fail:** Note what's missing (e.g., "No version prefix in any URL path. No version headers. 14 endpoints at `/api/resource` with no versioning. When breaking changes are needed, there's no mechanism to protect existing consumers."). Max 500 chars.
- **Remediation:** Add URL-based versioning (the most straightforward approach) to all endpoints now, before you have external consumers:

  ```
  // Before:
  /api/users
  /api/orders

  // After:
  /api/v1/users
  /api/v1/orders
  ```

  For GraphQL, version via `@deprecated` directives on fields and a documented deprecation timeline rather than URL versioning.

  For gRPC, use package versioning: `package myapi.v1;` in your `.proto` files.

## External references

- iso-25010 compatibility.interoperability
- iso-25010 maintainability.modifiability

Taxons: code-quality

HTML version: https://auditbuffet.com/patterns/ab-000365
