Script Valley
REST API Development: Beginner to Production
Data Validation, Error Handling, and API Design PatternsLesson 3.5

API versioning strategies โ€” URL vs header versioning

URL versioning, header versioning, Accept header, version deprecation, breaking vs non-breaking changes, versioning tradeoffs

API Versioning Strategies

Once an API has consumers, breaking changes require a new version. The choice of versioning strategy affects discoverability, caching, and client migration friction.

URL Versioning

The most common approach. Version is part of the path: /api/v1/users. Easy to test in a browser, easy to route at the infrastructure level, clearly visible in logs.

// Mount v1 and v2 routers separately
const v1Router = require('./routes/v1');
const v2Router = require('./routes/v2');

app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);

Header Versioning

Version is passed in an HTTP header, typically Accept or a custom API-Version header. Keeps URLs clean but makes versioning invisible to casual users and harder to test without tooling.

// Middleware to route by version header
app.use('/api/users', (req, res, next) => {
  const version = req.headers['api-version'] || '1';
  if (version === '2') {
    return v2UserController.handle(req, res, next);
  }
  v1UserController.handle(req, res, next);
});

URL versioning is the right default for public APIs โ€” it's explicit and easy to document. Reserve header versioning for internal APIs where you control all clients. Always document a deprecation timeline before removing old versions; give consumers at least six months.

API versioning strategies โ€” URL vs header versioning โ€” Data Validation, Error Handling, and API Design Patterns โ€” REST API Development: Beginner to Production โ€” Script Valley โ€” Script Valley