How do you version a Web API?

Web API & REST API Design Advanced 3–5 Yrs5+ Yrs Scenario 2 min read

Quick Answer

Pick one scheme and be consistent: URL path (/api/v2/orders) — most visible and cache-friendly; query string (?api-version=2.0); header (api-version: 2.0) — keeps URLs clean; or media type (Accept: application/vnd.myapp.v2+json). Only version on breaking changes; additive changes don't need a new version. In ASP.NET Core the Asp.Versioning library handles all four.

First, I only version on breaking changes — removing a field, changing a type, changing what a value means. Adding a new optional field or a new endpoint shouldn't force a version bump, and clients should be built to ignore fields they don't know. For the scheme, I usually go with the URL path, like /api/v2/orders, because it's the most visible, it's easy to route and cache, and you can hit it straight from a browser. Header or media-type versioning is cleaner in theory but people forget to send the header. Whatever I pick, I support the current and previous version during a deprecation window and communicate a sunset date. In ASP.NET Core the Asp.Versioning package supports all of these.

When to bump the version: removing or renaming a field, changing a type, changing the meaning of a value, removing an endpoint, making an optional field required. Not for adding a new optional field or a new endpoint — clients should tolerate those.

Trade-offs:

  • URL path — obvious, easy to route and cache, easy to test in a browser; “pollutes” the URL and implies the resource changed.
  • Header / media type — purists' choice, keeps one URL per resource; harder to explore, easy for clients to forget.
  • Query string — simple, but mixes versioning with filtering params.

Practices: support N and N-1 during a deprecation window; document the sunset date (Sunset header); keep controllers per version or use API version mapping; share DTO-mapping code so v1 and v2 don't diverge silently.