API compatibility without a second API

Change your API without breaking old clients.

Keep one API. Versionless handles old clients.

No v1 folders. No duplicate handlers. No old-shape branches.

bun add @versionless/core

One current handler

Old shape in. New shape out.

Versionless updates the payload before your handler sees it.

One payload. One automatic change.request →
OLD APP SENDS
name: "Ada Lovelace"
VERSIONLESSsplits the name
YOUR API RECEIVES
firstName: "Ada"
lastName: "Lovelace"
namefirst + last
Old clients keep their old fields.Your code only sees the new ones.
Responses run backward automatically.

Make the breaking change

Write the API you want.

Add one small translation. Old clients keep working.

changes/2026-05-14.tsrequest up · response down
export default v.change("2026-05-14", {
  request: {
    up: ({ name, ...user }) => {
      const [firstName, ...lastName] = name.split(" ");
      return { ...user, firstName, lastName: lastName.join(" ") };
    },
  },
  response: {
    down: ({ firstName, lastName, ...user }) => ({
      ...user, name: `${firstName} ${lastName}`,
    }),
  },
});

Why it matters

One API for you. No forced upgrades for customers.

01

No more v1, v2, v3, v4 forever.

Instead of/v1/customers /v2/customers /v3/customers
You have/customers

Build only the latest API. Versionless handles old clients.

02

No forced customer migrations.

Without Versionless"We're deprecating v1 in 6 months."

Every customer scrambles to migrate.

With Versionless
  • Old SDKs keep working.
  • Old integrations keep working.
  • Customers upgrade when they want.

You own the compatibility work—not every customer.

03

Refactor without fear.

Change the API and the architecture behind it.

  • rename fields
  • split endpoints
  • merge endpoints
  • move from sync to async
  • redesign internal models

Improve the implementation without being trapped by old contracts.

Your next breaking API change

Ship it like a normal code change.

Versionless adds one compatibility step to the workflow you already have.

  1. 01
    Change today's schema and handler.

    Build the API you actually want to maintain.

    name → firstName + lastName
  2. 02
    Run the surface check in CI.

    It tells you what old clients would lose.

    bunx versionless check
  3. 03
    Add one reversible translation.

    Request in. Response out. Kept at the edge.

    changes/2026-05-14.ts
  4. 04
    Merge the current API.

    New clients move forward. Old clients keep working.

    ✓ safe to ship

Keep one API

Your product moves forward. Your clients move when ready.

start with the docs read the source