Query Parameter Versioning

Lifecycle & Versioning Jan 6, 2025 HTTP

Definition

When you need to version your API but don’t want to clutter your URL paths with /v1/ or /v2/ prefixes, query parameter versioning offers an elegant alternative. Instead of changing the endpoint itself, you simply add a version parameter to your requests: /products?version=2 or /users?api-version=2.1. The base URL stays clean, and clients explicitly declare which version they want with each request.

This approach sits somewhere between path-based versioning (like /v1/products) and header-based versioning (using custom headers). It’s more visible than headers since you can see it right in the URL, but more flexible than path versioning since you don’t need different route handlers for each version. The version travels with the request in plain sight, making debugging easier - you can look at logs or browser developer tools and immediately see which version was called.

Query parameter versioning is particularly popular with APIs that want to make versioning optional. Many implementations default to the latest stable version when no parameter is provided, only requiring explicit version specification when clients need backward compatibility. This makes the API feel simpler for new integrations while giving power users the control they need. The tradeoff is that versions can be easily overlooked or forgotten, and caching becomes trickier since the same path can return different content based on the parameter.

Example

Azure Cloud APIs: Microsoft Azure uses query parameter versioning across most of their services. When you call Azure Storage, you include ?api-version=2023-11-03 with every request. This allows Azure to maintain dozens of API versions simultaneously - critical for enterprise customers who can’t update their integrations overnight. If you forget the version parameter, Azure returns an error telling you which versions are available.

Google Cloud APIs: Many Google Cloud services use a similar pattern. Cloud Storage accepts ?v=2 or ?v=3 parameters. What’s clever is how they handle defaults - some endpoints default to the latest version for new features while others require explicit versioning for stability-critical operations like data manipulation.

AWS API Gateway: When you build APIs on AWS API Gateway, query parameter versioning is a first-class option. You can configure stage variables that map version parameters to different Lambda functions or backend services. A request to /products?version=1 might route to your Node.js legacy service while ?version=2 routes to your new Go service.

Stripe’s Special Parameters: While Stripe primarily uses header-based versioning, they use query parameters for specific opt-in features. Parameters like ?expand[]=customer or ?stripe_version=2023-10-16 give clients fine-grained control over response format and behavior. This hybrid approach gives the best of both worlds.

Internal Enterprise APIs: Many large companies use query parameter versioning for internal APIs because it’s easy to implement and debug. A call like /api/employees?v=3&department=engineering makes it obvious in logs which version was called. When something breaks in production, engineers can immediately see the version without digging through request headers.

Analogy

The Restaurant Menu with Sections: Imagine a restaurant where the menu has evolved over time. Instead of reprinting everything or having separate “classic menu” and “new menu” booklets, they have one unified menu where you can specify your preference. “I’ll have the pasta” defaults to the current recipe, but you can say “I’ll have the pasta, original recipe” to get the classic version. The dish name stays the same; your preference is noted separately.

The Streaming Service Quality Selector: When you watch Netflix or YouTube, the video URL is the same, but you can add quality preferences. video.mp4?quality=720p vs video.mp4?quality=4k fetches the same content in different formats. Query parameter versioning works identically - same endpoint, different behavior based on the parameter you provide.

The Building with Multiple Elevators: Think of an office building where all elevators go to all floors, but some are express. You press your floor (the endpoint), then select express or local (the version parameter). The destination is the same; the parameter changes how you get there. Old clients use the local elevator (stable version); new clients can choose express (latest version).

Software Installation Options: When you download software, you often choose between “Standard Install” and “Custom Install.” The download URL might be the same, but ?type=standard vs ?type=custom changes what you get. You’re requesting the same product with different configurations - exactly how query parameter versioning works for APIs.

Code Example


// Query parameter versioning
GET https://api.company.com/products?version=1
GET https://api.company.com/products?version=2
GET https://api.company.com/products?api-version=2.1

// Can combine with other parameters
GET https://api.company.com/products?version=2&limit=50&category=electronics

// Default version when omitted
GET https://api.company.com/products  // Uses latest stable (v2)

// Error response for unsupported version
GET https://api.company.com/products?version=99
[HTTP/1.1](https://reference.apios.info/terms/http-1-1/) 400 Bad Request
{
  "error": "UnsupportedVersion",
  "message": "Version 99 is not supported. Available: 1, 2",
  "supportedVersions": [1, 2]
}

Standards & RFCs

Standards & RFCs
3)- Azure [REST](https://reference.apios.info/terms/rest/) API Guidelines - Query parameter versioning reference