Introduction
As an API evolves, breaking changes are sometimes unavoidable — renamed fields, changed response shapes, or removed endpoints. API versioning lets you introduce these changes without breaking existing clients. Combined with other best practices, versioning helps keep an Express API maintainable, discoverable, and stable over time.
Cricket analogy: When the ICC changes LBW rules, older matches played under the old rule aren't retroactively invalidated — a new rulebook version is issued so umpires and players on either side stay in sync without disrupting ongoing tournaments.
Syntax
const express = require('express');
const app = express();
const usersV1 = require('./routes/v1/users');
const usersV2 = require('./routes/v2/users');
app.use('/api/v1/users', usersV1);
app.use('/api/v2/users', usersV2);Explanation
The most common versioning strategy is URL path versioning (e.g. /api/v1/..., /api/v2/...), which is explicit and easy to route with express.Router(). Other strategies include header-based versioning (e.g. an Accept-Version header) and query-parameter versioning, both of which keep URLs cleaner but are less discoverable. Regardless of strategy, best practices include: using express.Router() to organize each version's routes into its own module, documenting deprecations clearly, maintaining backward compatibility within a major version, and never introducing breaking changes without bumping the version.
Cricket analogy: Just as a scorecard clearly labels "1st Innings" vs "2nd Innings" so nobody confuses which set of overs a stat belongs to, URL path versioning like /api/v1/ labels requests explicitly, while header-based versioning is like an umpire's private signal only insiders notice.
Example
// routes/v1/users.js
const router = require('express').Router();
router.get('/', (req, res) => {
res.json({ version: 'v1', users: ['Alice', 'Bob'] });
});
module.exports = router;
// routes/v2/users.js (response shape changed: now includes pagination)
const router = require('express').Router();
router.get('/', (req, res) => {
res.json({ version: 'v2', data: ['Alice', 'Bob'], page: 1, total: 2 });
});
module.exports = router;Output
GET /api/v1/users returns { "version": "v1", "users": ["Alice", "Bob"] }, while GET /api/v2/users returns the new shape { "version": "v2", "data": ["Alice", "Bob"], "page": 1, "total": 2 }. Existing v1 clients keep working unchanged while new clients can adopt v2 at their own pace.
Cricket analogy: Just as Test cricket and T20 scorecards report stats in different formats for the same players, GET /api/v1/users returning a simple list and /api/v2/users returning a paginated object let old and new clients read the data shaped the way they expect.
Key Takeaways
- URL path versioning (/api/v1/...) is the most common and discoverable strategy.
- express.Router() makes it easy to organize each API version as an independent module.
- Breaking changes should always trigger a new version rather than modifying an existing one.
- Document deprecations and give clients a migration window before removing old versions.
- Consistent response shapes, error formats, and status codes within a version reduce client confusion.
Practice what you learned
1. Which is the most common and discoverable API versioning strategy?
2. What Express feature is commonly used to organize routes for different API versions?
3. What should happen when a breaking change is needed in an API's response shape?
4. Which of the following is a best practice for maintaining an Express API long-term?
Was this page helpful?
You May Also Like
RESTful API Design
Learn the core principles of REST: resource-based URLs, proper HTTP methods, and meaningful status codes.
Express Application Structure
Learn how to organize a growing Express project into routes, controllers, middleware, and config folders.
Routing in Express
Understand how Express matches HTTP methods and URL paths to handler functions using routes.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics