API Versioning: Why It Matters and How to Get It Right

Every API evolves. Fields get renamed, endpoints get restructured, authentication methods change. Without a versioning strategy, every change risks breaking your consumers' integrations. Versioning is your contract with clients: "this version will keep working the way you expect."

There are three primary versioning strategies in widespread use. Each has genuine advantages and real trade-offs.

Strategy 1: URI Path Versioning

The version number is embedded directly in the URL path:

GET /v1/users/123
GET /v2/users/123

Pros:

  • Immediately visible — the version is obvious from the URL alone
  • Easy to test in a browser or with curl
  • Simple to route at the gateway or reverse proxy level
  • Can be cached by CDNs and proxies without configuration

Cons:

  • URLs are technically supposed to identify resources, not representations — purists argue this violates REST principles
  • Can result in URL sprawl as versions multiply

Used by: Stripe (/v1/), Twilio, GitHub, most major public APIs. This is the de facto standard for a reason — simplicity wins.

Strategy 2: HTTP Header Versioning

The version is specified in a custom request header, keeping URLs clean:

GET /users/123
Accept-Version: 2
# or
API-Version: 2025-01-01

Pros:

  • URLs remain stable and "pure" — the resource URL doesn't change
  • Aligns with HTTP content negotiation semantics
  • Supports date-based versioning (e.g., Stripe uses this for their API version dates)

Cons:

  • Harder to test — you can't just paste a URL in a browser
  • CDN caching is more complex (requires Vary headers)
  • Less discoverable for new API consumers

Used by: Stripe's supplemental versioning (date-based), some enterprise APIs. Often combined with URI versioning.

Strategy 3: Query Parameter Versioning

The version is passed as a query string parameter:

GET /users/123?version=2
GET /users/123?api-version=2024-01

Pros:

  • No URL structure changes
  • Easy to add to existing clients
  • Optional — can fall back to a default version if omitted

Cons:

  • Can clutter URLs, especially when combined with other query params
  • Caching behavior varies — query strings may or may not be cached by proxies
  • Less explicit than URI versioning

Used by: Microsoft Azure REST APIs, some Google APIs. Common in enterprise settings.

Comparison at a Glance

StrategyDiscoverabilityCachingREST PurityEase of Use
URI PathHighExcellentModerateHigh
HTTP HeaderLowComplexHighModerate
Query ParamMediumVariableModerateHigh

Best Practices Regardless of Strategy

  1. Define your deprecation policy upfront. Tell consumers how long old versions will be supported before sunset.
  2. Use semantic versioning or date-based versioning consistently. Don't mix v2 and 2024-01-15 in the same API.
  3. Make breaking vs. non-breaking changes explicit. Adding optional fields is non-breaking; removing required fields is breaking.
  4. Communicate changes proactively. Changelogs, email notifications, and Sunset headers (Sunset: Sat, 31 Dec 2025 23:59:59 GMT) are all useful signals.
  5. Version from day one. Even if you start with v1 and never bump it, it sets the expectation that versions exist.

For most APIs, URI path versioning is the pragmatic choice — it's clear, cacheable, and what developers expect. Save header-based versioning for situations where URL stability is a hard requirement.