hectoday
DocsCoursesChangelog GitHub
DocsCoursesChangelog GitHub

Access Required

Enter your access code to view courses.

Invalid code

← All courses API versioning and evolution with @hectoday/http

Why versioning

  • Breaking changes
  • The versioning contract
  • Project setup

Versioning strategies

  • URL path versioning
  • Header versioning
  • Query parameter versioning
  • Choosing a strategy

Building versioned APIs

  • Side-by-side versions
  • Version routers
  • Validation per version

Evolving without breaking

  • Additive changes
  • Deprecation
  • Field renaming and removal
  • Changing response shapes

Lifecycle management

  • Sunset policies
  • Monitoring version usage
  • Checklist

The versioning contract

What you promise

When you publish an API, you’re making an implicit promise to every developer who uses it: “If you build against this API, it will keep working.” That sounds obvious, but it’s surprisingly easy to break that promise without realizing it.

Versioning makes this promise explicit. Each version is a contract, a guarantee that the request and response shapes won’t change in breaking ways. If you need to make a breaking change, you create a new version. The old one keeps working.

Backward compatibility

A change is backward compatible if existing clients continue to work without any modifications after the change. The rule from the previous lesson applies directly here: additive changes are backward compatible, subtractive changes are not.

But there’s an important nuance. Backward compatibility is a one-way promise. You promise that old clients work with new API versions. You do not promise that new clients work with old API versions. That second thing is called forward compatibility, and it’s a much harder promise to make.

A client built for v2 can’t call v1 if v2 has features that v1 doesn’t support. That’s expected. The promise only flows backward: old clients always work.

Semantic versioning for APIs

You might have seen version numbers like 2.3.1 on npm packages. That’s semantic versioning, and it uses three numbers: MAJOR.MINOR.PATCH.

MAJOR (v1 to v2): Breaking changes. Removed fields, changed types, restructured responses. Clients must update their code to use this version.

MINOR (v1.1 to v1.2): New features that are backward compatible. Added fields, new endpoints, added optional parameters. Existing clients keep working without changes.

PATCH (v1.1.0 to v1.1.1): Bug fixes with no API changes. A bug in the rating calculation gets fixed, but the response shape stays the same.

In practice, most APIs only version with the major number: v1, v2, v3. Minor and patch changes happen within a version without bumping the version number, because they’re backward compatible and don’t require any client changes. You just deploy them, and everything keeps working.

The contract per version

Let’s make this concrete with our book catalog API. Each version has a specific contract that clients depend on:

v1 contract:

  • GET /v1/books returns [{ id, title, author_name, rating }]
  • POST /v1/books accepts { title, author_id }, returns 201 with { id, title }
  • author_name is a string, rating is a number

v2 contract:

  • GET /v2/books returns [{ id, title, author: { id, name }, ratings: { average, count } }]
  • POST /v2/books accepts { title, authorId }, returns 201 with { id, title, author }
  • author is a nested object, ratings is a nested object

Both contracts exist at the same time. v1 clients call v1 endpoints. v2 clients call v2 endpoints. Neither breaks. That’s the whole point of versioning.

When to create a new version

You should create a new major version when you need to make a breaking change that can’t be done additively. Here are the common triggers:

Restructuring responses: Flattening nested objects, changing from arrays to objects, adding pagination wrappers.

Renaming fields: Changing from snake_case to camelCase, or from abbreviated names to full names.

Changing authentication: Moving from API keys to OAuth, changing token formats.

Changing error formats: Restructuring error responses, changing error codes.

What about adding fields, adding endpoints, adding optional parameters, fixing bugs, or improving performance? Those are all backward compatible. They belong in the current version. Don’t create a new version for things that won’t break anyone.

[!NOTE] The REST API Design course established conventions for response formats, pagination, and error shapes. Changing any of those conventions for existing endpoints requires a new version.

Next, we’ll set up the project we’ll use throughout the rest of this course, a book catalog API that already has clients depending on it.

Exercises

Exercise 1: Write the contract for a v1 API with 3 endpoints. Specify the request and response shapes.

Exercise 2: Identify three changes that would require a v2. Identify three changes that fit within v1.

Exercise 3: A client was built against v1 six months ago. They haven’t updated since. What do they expect from the API?

When should you create a new major API version?

← Breaking changes Project setup →

© 2026 hectoday. All rights reserved.