Public APIs
All posts

API Versioning Best Practices (With Real Examples)

Quick answer: version your API only when you make a breaking change, put the version somewhere explicit (a /v1/ path segment is the pragmatic default, a date-pinned header is the scalable one), never change existing behavior silently, and announce deprecations with real dates and Sunset headers. Everything else is detail, covered below.

Versioning is the contract problem behind every public API: you need to evolve, and the thousands of clients you do not control need yesterday's behavior to keep working. Browsing the 1,600+ APIs listed on Public APIs, a /v1/ or /v2/ path segment is the pattern you will meet most often, but the strategies actually in production vary more than most tutorials admit.

When do you actually need a new API version?

Only for breaking changes. A change breaks clients when it:

  • removes or renames a field, endpoint, or parameter
  • changes a field's type, format, or meaning
  • makes a previously optional input required
  • changes authentication requirements or error semantics

Additive changes (new endpoints, new optional parameters, new fields in responses) do not need a version bump, provided you commit to one rule and document it: clients must ignore fields they do not recognize. Teams that version on every release end up with a graveyard of near-identical versions; teams that never version end up breaking clients silently. Version on breakage, and only on breakage.

What are the main API versioning strategies?

URI path versioning

The version lives in the path: api.example.com/v1/users. It is explicit, visible in logs and docs, trivially cacheable, and every client understands it instantly. The cost is philosophical more than practical: the same resource now has two URLs. This is the default choice for most public APIs, and the right one if your audience includes beginners.

Header or media-type versioning

The URL stays clean and the version moves into a request header. GitHub's REST API is the best-known example: clients send an X-GitHub-Api-Version header with a date value, and requests without it get the default version. This keeps resource URLs stable and pleases REST purists, at the cost of being invisible: a curl command without the header silently hits whatever the default is.

Date-based version pinning

Stripe popularized this model: each account is pinned to the API version that was current when it first made a request, and every breaking change ships as a new dated version. Clients upgrade deliberately, whenever they are ready. It is the most client-friendly model and the most work to operate, because the provider maintains translation layers between many dated versions. Choose it when your API is your product and you have the engineering budget to back that promise.

Query parameter versioning

?version=2 appended to the URL. It works, but it interacts poorly with caches, gets stripped by intermediaries, and clutters every example. It survives mostly in older enterprise APIs; there is little reason to pick it for something new.

Which strategy should you pick?

  • Small or new public API: URI path versioning. Ship /v1/ from day one so introducing /v2/ later is a routine event instead of a redesign.
  • Developer-platform API with long-lived integrations: header or date-based pinning, because URL stability and deliberate client upgrades matter more than curl-friendliness.
  • Internal API with few consumers: often no versioning at all, just additive evolution plus coordination with the teams involved.

Whatever you choose, choose once. Mixing strategies (a /v2/ path here, a version header there) is the one option that is strictly worse than any single strategy.

How do you deprecate an old API version gracefully?

Retiring a version is where versioning strategies earn their keep:

  1. Announce early, with dates. A changelog entry and an email beat any header, because humans plan migrations, machines only fail them.
  2. Send machine-readable signals. Return a Deprecation header on old-version responses and a Sunset header (standardized in RFC 8594) with the shutdown date, so client libraries and monitors can alert automatically.
  3. Publish a migration guide that maps every breaking difference from the old version to the new one, with before-and-after request examples.
  4. Watch real usage before the shutdown. Traffic on the old version tells you which consumers have not migrated; reaching out to the loudest ones beats surprising them.
  5. Fail loudly at the end. When the sunset date arrives, return a clear error with a link to the migration guide, not a silently different response.

Public APIs that skip step 2 force every consumer to build calendar reminders out of blog posts. The headers cost minutes to add and are the difference between a managed migration and a support fire.

What are the most common API versioning mistakes?

  • Versioning every release. Version numbers are for breakage, not for marketing. SemVer-style minor and patch numbers belong in changelogs, not URLs.
  • Breaking behavior without a version bump. Changing a date format or tightening validation inside v1 is a breaking change, however small it feels.
  • No documented default. If requests without an explicit version get served, document exactly what they get and how stable that default is.
  • Keeping old versions alive forever, silently. An unmaintained v1 that still answers requests is a security surface and a data-consistency risk. Deprecate it properly instead.
  • Forgetting errors are part of the contract. Changing error codes or response shapes breaks clients just as hard as changing success payloads.

If you are building your first API, the 163 development APIs listed on Public APIs are a useful field study: open a few of their docs and note how each one handles versions, defaults, and deprecation notices. Patterns you see three times are conventions; patterns you see once are opinions. The authentication and authorization category pairs well with this exercise, since auth changes are among the most common breaking changes in the wild.

FAQ

Is a /v1/ path RESTful?

Strict REST theory says a version does not belong in a resource identifier, and header-based versioning is the purist answer. In practice, path versioning is used by a large share of successful public APIs because explicitness wins for onboarding and debugging. Both are legitimate; pick based on your audience, not the argument.

Should I version my API from day one?

Expose /v1/ (or a default version label) from launch. It costs nothing, sets client expectations, and turns your first breaking change from an architecture crisis into a routine release.

Does semantic versioning apply to APIs?

Loosely. Consumers of a hosted API only experience major versions, because minor and patch changes are additive by definition. Keep SemVer for your SDKs and changelogs; keep the API surface to simple, rarely-changing major versions.

How long should old API versions be supported?

There is no standard, but public APIs commonly promise 6 to 12 months between deprecation notice and sunset. The commitment matters more than the number: pick a window you can honor, publish it, and honor it.