Back to Blog
Apr 10, 20264 min readOnuzulike Anthony

API Versioning: How to Evolve an API Without Breaking Clients

URL path versioning, header versioning, query params, semantic versioning, and the Sunset header — what each approach costs and when to use it.

ArchitectureArchitectureAPIDesign

API versioning is a promise about how long your API will remain stable. Every versioning strategy is a trade-off between how easy it is for you to change things and how easy it is for clients to consume them. Getting this wrong means either a fragile API that breaks clients or a maintenance burden that never goes away.

Why You Need Versioning

Without versioning, any breaking change to your API breaks every client simultaneously. "Breaking change" includes:

  • Removing or renaming a field
  • Changing a field's type
  • Changing an endpoint's URL
  • Changing required vs optional parameters
  • Changing error response shapes

Additive changes — new optional fields, new endpoints, new optional query params — are generally non-breaking. Design your API to be additive by default.

URL Path Versioning (/v1/, /v2/)

The most common approach: the version is part of the URL.

GET /api/v1/users
GET /api/v2/users

Pros: Explicit. URLs are bookmarkable and loggable. Easy to route by version in a proxy or Next.js middleware. Immediately visible in network logs — you know exactly which version a request hit.

Cons: Version in the URL violates REST purists' sense of "a URL should identify a resource, not a version of that resource." More practically: it creates two different URLs for the same resource, complicating caching.

In Next.js App Router, implement with route groups:

app/
  api/
    v1/
      users/route.ts
    v2/
      users/route.ts

Header Versioning

The version is specified in a request header, leaving the URL clean:

http
GET /api/users
API-Version: 2026-04-01

Stripe uses date-based versioning in this style. The advantage: clients pin to a specific version date and see a stable API. Each "version" is a snapshot of the API on that date, and breaking changes are introduced as new dates.

Cons: Harder to test in a browser. Requires clients to know to set the header. Caches need to vary on the version header.

Query Parameter Versioning

GET /api/users?version=2

Easiest for clients to use (visible, easy to change). Works naturally in browser address bars. The main downside: caches may not vary on query params correctly without explicit Vary configuration.

Semantic Versioning and Breaking Changes

For libraries and SDKs, SemVer (MAJOR.MINOR.PATCH) signals breaking changes clearly: increment MAJOR for breaking changes, MINOR for new features, PATCH for fixes.

For HTTP APIs, SemVer maps less cleanly because clients can't "upgrade" a server the way they upgrade a library. Version numbers in API URLs tend to be integers (v1, v2) that increment on major breaking changes, not SemVer.

The Sunset Header

When you deprecate a version, tell clients:

http
HTTP/1.1 200 OK
Sunset: Sat, 31 Dec 2026 23:59:59 GMT
Deprecation: Wed, 01 Jan 2026 00:00:00 GMT
Link: <https://api.example.com/v2/users>; rel="successor-version"

Sunset is an IETF standard (RFC 8594). It tells clients: this endpoint will stop working on this date. Good API clients log or alert on this header so their operators know a migration is needed.

Version Overlap Periods

When releasing a new version, run old and new simultaneously for a migration window. The length depends on your client base:

  • Internal APIs: 2–4 weeks (you control the clients)
  • Partner APIs: 3–6 months (they need planning time)
  • Public APIs: 6–12 months (unknown clients, conservative)

After the sunset date, return 410 Gone rather than continuing to serve the deprecated endpoint. This makes the retirement explicit — a 404 suggests the URL never existed; a 410 says it used to and is now intentionally gone.

What Not to Version

Don't version things that don't need it. If an API change is backward-compatible (new optional field, new endpoint), there's no need to bump the version. Over-versioning creates unnecessary maintenance burden — every version in active use is a code path you maintain.

ApiShield's HAR parser and live probe features were added without versioning because they extended the input format detection non-breakingly. Only changes to the normalized spec format or the report structure would require versioning the tool's API surface.