100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Node.js

API Versioning and Best Practices

Learn common strategies for versioning Express APIs and best practices for building maintainable endpoints.

Building APIsIntermediate10 min readJul 8, 2026
Analogies

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

javascript
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

javascript
// 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

Was this page helpful?

Topics covered

#NodeJs#NodeJsExpressStudyNotes#WebDevelopment#APIVersioningAndBestPractices#API#Versioning#Syntax#Explanation#APIs#StudyNotes#SkillVeris