You shipped v1 of your API. Now you need breaking changes. Do you break existing clients or maintain two versions forever?
Strategy 1: URL Path Versioning
/api/v1/users vs /api/v2/users
Pros: Explicit, easy to route, clients see version in URL. Used by: Stripe, GitHub, Twilio.
Cons: URL bloat, hard to share code between versions.
Strategy 2: Header Versioning
Accept: application/vnd.myapi.v2+json or X-API-Version: 2
Pros: Clean URLs, version negotiation possible. Used by: GitHub (Accept header).
Cons: Hidden complexity, harder to test in browser, easy to forget.
Strategy 3: Query Parameter
/api/users?version=2
Pros: Easy to implement. Cons: Breaks caching, pollutes query string. Not recommended.
Strategy 4: Date-Based (Stripe Style)
Stripe-Version: 2024-12-18
Each API key is pinned to the version at creation time. Clients upgrade by changing the version header. Rolling changes, not big-bang migrations.
Implementation: Express Router-Based Versioning
import { Router } from "express";
const v1 = Router();
const v2 = Router();
v1.get("/users", (req, res) => res.json({ users: [{ name: "Alice" }] }));
v2.get("/users", (req, res) => res.json({ data: [{ firstName: "Alice", lastName: "Smith" }], meta: { total: 1 } }));
app.use("/api/v1", v1);
app.use("/api/v2", v2);
Deprecation Strategy
- Add Sunset header:
Sunset: Sat, 01 Jun 2026 00:00:00 GMT - Add Deprecation header:
Deprecation: true - Log usage of deprecated endpoints
- Email affected API key owners 90, 30, and 7 days before sunset
My Recommendation
Start with URL path versioning. It is explicit, debuggable, and every developer understands it. Move to date-based versioning when you need fine-grained control. Avoid query parameters.
Part of my Production Backend Patterns series. Follow for more practical backend engineering.
If this was useful, consider:
- Sponsoring on GitHub to support more open-source tools
- Buying me a coffee on Ko-fi
You Might Also Like
- API Rate Limiting with Redis: Token Bucket, Sliding Window, and Per-Client Limits
- API Rate Limiting with Redis: Token Bucket, Sliding Window, and Per-Client Limits (2026)
- CORS Explained Simply: Why Your Frontend Can't Talk to Your API (Fix in 5 Minutes)
Follow me for more production-ready backend content!
If this helped you, buy me a coffee on Ko-fi!
Top comments (0)