Hard20 minExpress.js Fundamentals
UpdatedAug 5, 2026
Edit

Express API Versioning

Question Variations

  • "When does an API change require a new version?"
  • "How would you support `/v1` and `/v2` in Express?"
  • "How do you sunset an old API version without surprising clients?"

Why This Is Asked

Public API changes require compatibility planning beyond adding a new route. This question assesses how you communicate contracts, isolate incompatible behavior, and retire versions safely.

Key Concepts

  • A version represents a compatibility contract, not a deployment number.
  • URL prefixes, media types, and headers are possible versioning mechanisms.
  • Breaking changes need an explicit migration and deprecation plan.
  • Shared domain logic should not be duplicated merely because transport versions differ.

Question Variations

  • “When does an API change require a new version?”
  • “How would you support /v1 and /v2 in Express?”
  • “How do you sunset an old API version without surprising clients?”

Answers by Technology

+ Add Variant
Express.jsImprove this answer ✏️

Expected Answer (Express 5.1.0 / Node.js 18+)

Version an API when a change breaks an existing client contract: removing or renaming fields, changing their meaning or type, altering required inputs, or changing observable behavior. For HTTP APIs, a URL prefix such as /api/v1 is often the clearest operational choice because route ownership, documentation, metrics, and deprecation can be separated. Header or media-type versioning can work but is harder for clients and tooling to discover.

Mount each transport version on a router, while sharing domain services and validation primitives where their behavior is genuinely compatible. Do not duplicate the entire application. Publish a sunset date, document migration paths, report usage per version, and notify consumers before removing a deprecated version. Adding optional fields is often backward compatible, but clients that validate responses strictly may still need communication.

Why It Matters

Versioning avoids breaking deployed clients while allowing the service to evolve. A deprecation plan prevents old contracts from becoming permanent operational debt.

Code Example

import express, { Request, Response } from 'express';

const app = express();
const v1 = express.Router();
const v2 = express.Router();
v1.get('/users/:id', (req: Request, res: Response) => res.json({ id: req.params.id, name: 'Ada' }));
v2.get('/users/:id', (req: Request, res: Response) => res.json({ id: req.params.id, profile: { name: 'Ada' } }));
app.use('/api/v1', v1);
app.use('/api/v2', v2);
app.listen(3000);

Common Mistakes

  • Creating a new version for every additive field: It adds unnecessary client and operational complexity.
  • Removing a version without usage evidence or notice: Long-lived integrations can fail without a migration window.

Follow-up Questions

  • What is a breaking response change? (Answer: A removed, renamed, or semantically changed field that clients depend on.)
  • Why use routers for versions? (Answer: They isolate HTTP contracts while allowing shared application logic.)