Back to the map

Module 04 · API fundamentals · Lesson 5 of 15

API versioning and evolution

Most changes should never need a version. The additive-change rules that keep clients working, the three places a version can live when you must break something, and how to retire old versions without a cliff.

CoreShould-knowMid 10 min Updated Nov 2026

Why it matters

The day after an API has a second consumer, you can no longer change it freely. Versioning is how you keep improving the API without breaking the people who built on yesterday's. Done badly it produces a zoo of versions nobody dares remove; done well it is mostly invisible, because the vast majority of changes turn out not to need a version at all.

The idea

Separate two questions: which changes are compatible (and so need no version), and where the version lives for the changes that are not.

Most changes are compatible if you follow the rules

Compatible (no version needed)Breaking (needs a version)
Adding a new endpointRemoving or renaming an endpoint
Adding an optional request fieldAdding a required request field
Adding a response fieldRemoving or renaming a response field
Adding a new enum value the client can ignoreChanging the meaning or type of a field
Loosening validationTightening validation on existing input
Adding a new error code (in the documented envelope)Changing status codes for existing outcomes
The rule of thumb: you may add, you may not take away or redefine.

Two habits make additive evolution safe. Clients must ignore unknown fields (tolerant readers), and servers must never reuse a removed name for something different. With those in place, an API can grow for years on one version.

Where the version lives, when you need one

  1. 1

    In the URL: /v2/orders

    The most visible and the most common. Easy to route, cache and document; a version is a whole new surface, which encourages big-bang rewrites.
  2. 2

    In a header: Accept: application/vnd.example.v2+json or API-Version: 2024-06-01

    Keeps URLs stable and lets clients opt in per request. Harder to see in logs and browsers; date-based versions (Stripe's approach) let you pin behaviour per account and evolve continuously.
  3. 3

    In the schema: new fields and types alongside old

    GraphQL and protobuf avoid global versions by deprecating fields individually; the schema is the version. Works when the API is a typed graph and clients can see deprecation metadata.
Old clientNew client/v1/v2v1 adaptermaps to v2 shapev2 handlersOne modelone database
Both versions run against the same storage during the deprecation window; v1 is a thin adapter over v2's model, not a second system.

Retiring versions

A version with no sunset date is permanent. Announce deprecation with a date (6 to 12 months for public APIs), return a Deprecation or Sunset header on old-version responses so automated clients notice, measure traffic per version and contact the holdouts, then return 410 Gone after the date. Internally, two active versions is a healthy maximum; three means something has stalled.

Trade-offs

URL versions are discoverable and encourage coarse, infrequent breaks; header versions are flexible and encourage many small, less visible ones. Running two versions doubles test surface and support load for the window, which is why the first job is avoiding breaks altogether. Deprecation deadlines annoy a few consumers and save everyone else from carrying dead code forever.

In an interview

Lead with the compatibility rules, not the version scheme: "Additive changes only, clients ignore unknown fields, so most evolution needs no version. For a genuine break I would add /v2, run v1 as an adapter over the same model, send Sunset headers, and remove v1 after six months once traffic is near zero." That shows you have retired a version, which is rarer than having created one.

Check yourself

A team adds a new optional field to a response and a new optional query parameter to a request. A consumer's client crashes because it rejects unknown fields. Who should change?

API versioning and evolution · Backplane