
How to Implement API Versioning: URL Path, Query Parameter, and Custom Header Strategies
As your software application grows, requirements change. You will need to modify database schemas, rename parameters, or alter response layouts.
If you push these changes to a production API directly, you will trigger Breaking Changes that crash active mobile applications and third-party developer integrations.
To evolve backend services safely, you must implement API Versioning.
In this guide, we will analyze the three dominant API versioning strategies—URL Path, Query Parameter, and Custom Header—compare their impact on caching engines, and implement code setups for each in Node.js.
Strategy 1: URL Path Versioning (URI Routing)
URL path versioning inserts the version identifier directly into the entry point path structure.
GET https://api.example.com/v1/users
GET https://api.example.com/v2/usersAdvantages
- Simple Caching: Highly compatible with Content Delivery Networks (CDNs) and reverse proxies. Because the paths are completely distinct, caching keys resolve without configuration.
- Easy Testing: Developers can request specific versions directly from any standard web browser address bar.
Code Implementation (Express Router)
import express from 'express';
const app = express();
// Version 1 Controller
const v1Router = express.Router();
v1Router.get('/users', (req, res) => {
res.json({ users: [{ id: 1, name: 'Alex' }] });
});
// Version 2 Controller (Returning modified field naming)
const v2Router = express.Router();
v2Router.get('/users', (req, res) => {
res.json({ data: [{ userId: 1, userName: 'Alex' }] });
});
// Route binding
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);Strategy 2: Query Parameter Versioning
This strategy preserves a clean URL path and defines the target API version inside a query variable parameter.
GET https://api.example.com/users?version=2Advantages
- Clean Paths: The resource route (
/users) remains constant. - Default Fallbacks: You can configure your gateway to route requests lacking parameters to a default active version (e.g., falling back to
v1automatically).
The Downside: Caching Issues
Many corporate proxy servers and CDNs ignore query parameters when generating caching keys. If not configured correctly, a cached v1 response might be served to a user requesting v2.
Strategy 3: Custom Header Versioning (Media Type / Content Negotiation)
Also called "Accept Header Versioning", this approach keeps the URL completely clean. The version is requested inside custom HTTP headers.
GET https://api.example.com/users
Accept: application/vnd.myapi.v2+jsonAdvantages
- Strict REST Compliance: Follows the REST design philosophy that URLs should identify the resource location, not the representation version.
- Clean API Schema: The URL namespace remains untouched.
Code Implementation (Express Middleware)
import express from 'express';
const app = express();
const userControllerV1 = (req: any, res: any) => {
res.json({ users: [{ id: 1, name: 'Alex' }] });
};
const userControllerV2 = (req: any, res: any) => {
res.json({ data: [{ userId: 1, userName: 'Alex' }] });
};
app.get('/users', (req, res) => {
// Read target version from Accept Header
const acceptHeader = req.headers['accept'] || '';
if (acceptHeader.includes('vnd.myapi.v2+json')) {
return userControllerV2(req, res);
}
// Fallback to V1
return userControllerV1(req, res);
});The Downside: Testing and Caching Complexity
- Testing requires client tools (like Postman or curl) to modify request headers manually.
- To cache these routes, you must configure your reverse proxy to vary responses using the
Vary: Acceptheader, increasing configuration maintenance.
Versioning Strategies Comparison
| Metric | URL Path | Query Parameter | Custom Header |
| URL Cleanliness | Poor (cluttered) | Moderate | Excellent (clean) |
| CDN Cache-Friendliness | Excellent | Moderate | Poor (requires Vary setup) |
| Browser Accessibility | Yes | Yes | No (requires custom headers) |
| API Path Bloat | High | Low | Low |
Conclusion
Choose URL Path versioning for public web APIs where caching compatibility, routing, and testing simplicity are paramount. Select Custom Header versioning for enterprise microservices ecosystems where you want to maintain clean resource URLs and handle content representations dynamically.