Guide

API versioning and your SDK: picking a strategy that doesn't break consumers

Semver, calver, stable channels, URL versioning — how API versioning choices flow into SDK versioning, and what each one costs you.

Last reviewed: April 23, 2026

Key takeaways

  • API version and SDK version are different artifacts and do not need to share a number — but linking them is simpler than not.
  • Tracking `openapi.info.version` as the SDK's npm version is the cleanest strategy for generated SDKs. One number, one discipline.
  • Diff-based automatic semver is wrong roughly a third of the time in practice. Ship it only if you like being paged.
  • If `info.version` isn't a real release number in your team, fix that before debating versioning strategy — every strategy fails without it.
  • Version bumps aren't release notes. Consumers need a human-written changelog, ideally with migration guidance for breaking changes.

The question "what version is my SDK?" has two answers most teams conflate. The SDK's npm version is a package lifecycle artifact — it controls which tarball `npm install` pulls. The API's version is a contract artifact — it tells a consumer what shape to expect over the wire. Whether those two numbers should track each other, and how, is a decision most teams make implicitly by accident.

The result of accidental strategy is familiar: an SDK whose `1.4.3` has no relationship to any version the server returns, an `info.version` in the OpenAPI document that never changes, and a release note pipeline that shrugs at both. When a breaking change lands, nobody knows whether to bump to 2.0.0 or 1.5.0, and the decision is made by whoever ships first.

This guide walks through the strategies in the wild, what each one buys you, what it costs, and what "versioning correctly" actually looks like when you generate the SDK from an OpenAPI document.

API version and SDK version are different things

An API version is a property of the contract. It identifies the shape of requests and responses. Clients read it to decide which endpoint path to hit, which feature flags to expect, which error formats to accept.

An SDK version is a property of the distributed artifact. It identifies the tarball installed by `npm`. Consumers read it to decide whether to upgrade, whether a change is breaking, whether to pin.

They are not the same number and do not need to be. A team can ship SDK `1.7.2` on top of API `v3`, and SDK `2.0.0` can be an SDK-side breaking change on the same API `v3`. The relationship is a choice.

Strategies in the wild

Semver on the SDK, decoupled from the API. The SDK bumps when the SDK breaks — typically on generator upgrades or intentional API-surface refactors. API bumps are independent and signalled only by a new endpoint path (`/v2/…`) or header. This works well for SDKs that wrap a slow-moving, URL-versioned API. Breaking changes stay rare.

SDK version tracks the API's `info.version`. Whatever the OpenAPI document says `info.version` is, that's the npm version. One source of truth, no confusion — and zero work on the SDK side. The entire versioning discipline lives in the spec. This is the cleanest setup when the API is already versioned seriously (bumps gated through review, release notes attached).

Calver on both. `2026.4.23`-style. Useful for APIs that release continuously with no backwards-compatibility promise (internal-only SDKs, early-stage products). Loses the "this is safe to upgrade" signal semver gives you; gains a cleaner incident timeline.

Stable / beta channels. The SDK ships two tags (`@latest` and `@next`). The API lives at a single endpoint or two parallel endpoints. Consumers opt in to beta. Expensive to maintain — you're running two pipelines — but the only sane model when the API ships breaking changes fast and the SDK consumers can't afford to catch them live.

The trap: diff-based automatic semver

Every few months someone proposes a tool that bumps the SDK version automatically by diffing the OpenAPI document. Additive diff → minor. Breaking diff → major. No humans required.

Diff-based bumping is wrong about a third of the time in practice. Renaming a field reads as "removed + added" — a breaking change diff — but the semantic change might be zero (the backend accepted both names for a week as a compatibility shim). Making an optional field required reads as "no shape change" on naive differs — the property still exists — but it's a breaking change for every caller omitting it. Tightening an enum (removing a variant) reads as breaking but might be a no-op if no real data used that variant.

The honest tools therefore don't auto-bump. They surface the diff, classify it with best effort, and let a human decide. The human is the spec owner — the person who actually knows whether the rename is a shim or a break.

What we recommend when you generate from OpenAPI

If you're generating the SDK from an OpenAPI document, use the SDK-tracks-`info.version` strategy unless you have a specific reason not to. One number, one discipline, one release note trail. The spec author owns the bump — which is the right shape: they know what they changed.

If your API doesn't currently take `info.version` seriously, make it take `info.version` seriously before you pick a different strategy. An SDK whose version isn't a real release number is going to be confusing no matter how you bump it.

If you need a stable/beta split, run two SDK Factory apps pointed at two OpenAPI URLs (one stable, one next) publishing to different dist-tags or different package names. You keep the "one version per SDK" discipline at the app level and let the channel split happen at the publish level.

yamlopenapi.yaml (excerpt)
# Treat info.version as the SDK's npm version. Bump it in the same
# PR that introduces a breaking change — the SDK rebuild picks it up
# automatically the next time the schema is polled.
openapi: 3.1.0
info:
    title: Acme API
    version: 1.7.2   # ← this becomes the published npm version
servers:
    - url: https://api.acme.example/v1

Communicating breaking changes

A version bump is not a release note. A semver major says "this is breaking" but not "here is how to migrate" — and the second sentence is the one consumers actually need.

The minimal discipline that works: a `CHANGELOG.md` at a stable URL, one entry per published version, with a plain-English "what changed" block. If the SDK is generated, that changelog is generated by the human who bumps `info.version` — there's no tool that can infer intent from a schema diff, and tools that try produce noisy text nobody reads.

For meaningful breakages, migration guides with code samples beat a one-paragraph note. These live outside the OpenAPI document — in whatever documentation surface you already run — and should be linked from the release notes directly.

FAQ

Should I use semver or calver for my API?

Semver if you have a backwards-compatibility contract with consumers and care about it. Calver if your API changes continuously and the SDK's role is "stay current," not "be stable." Most public-facing APIs are semver; most internal-only APIs can get away with calver. Both are legitimate; picking badly is mostly a problem when consumers and producers assume different things.

What if my API doesn't have a version in the URL?

You have two options. Treat the single endpoint as an eternally-evolving contract and version the SDK from `info.version` — every breaking change bumps the major, consumers handle migration. Or introduce URL versioning before you hit a breaking change you can't announce. Most APIs that start unversioned hit the wall within a year; the earlier move is cheaper than the emergency move.

How do I signal a breaking change through the SDK?

Bump `openapi.info.version` to a new major, update the changelog in the same PR, and — if you can afford it — ship a deprecation warning under the old version before removing the old shape. The SDK consumer sees a major bump in their dependency bot's alert and can read the release note before upgrading. That's the whole contract.

Does SDK Factory auto-bump semver from the schema diff?

No. We read `info.version` from the spec and publish under that. Diff-based bumping is wrong often enough that we'd rather ship the boring-and-correct behaviour than the magic-and-sometimes-wrong one. The bump is the spec author's call, always.

Ready to stop maintaining the pipeline?

SDK Factory turns an OpenAPI URL into a versioned, auto-published TypeScript SDK. One app on the Free tier, no card required.