Semantic versioning, in plain English
Semantic versioning ("semver") is three numbers and one promise. The numbers are easy; the promise is where everyone argues. This guide explains what the spec actually commits you to, in plain English, plus the judgment calls the spec can't make for you.
The promise
A semver version is MAJOR.MINOR.PATCH, e.g. 2.4.1. Reading right
to left:
- PATCH (
2.4.1 β 2.4.2): "I fixed something. Nothing you depend on changed. Upgrade blind." - MINOR (
2.4.1 β 2.5.0): "I added something. Everything that worked still works. Upgrade blind; read the changelog if you want the new toys." - MAJOR (
2.4.1 β 3.0.0): "I broke something on purpose. Do not upgrade blind β read the migration notes first."
That's the entire contract. The version number is not marketing, not a birthday counter, and not a measure of effort. It answers exactly one question a downstream user has: "can I upgrade without reading anything?"
What actually counts as "breaking"
Breaking means: code or workflows that were correct before are wrong now. The subtle cases trip everyone up:
- Removing or renaming anything public β obviously breaking. Endpoints, exported functions, CLI flags, config keys, response fields. Removal should follow a published deprecation policy, not a mood.
- Changing a default β breaking. Users who never set the option relied on the old default, whether they knew it or not.
- Tightening validation β breaking. Input that used to be accepted now isn't; someone's pipeline sends exactly that input.
- Loosening validation, adding response fields, adding optional params β usually not breaking, and the reason well-designed APIs tell clients to ignore unknown fields.
- Fixing a bug people depended on β the classic judgment call. The spec says a fix is a patch; reality says if enough users rely on the buggy behavior, it's breaking for them (see "Hyrum's Law"). If the bug is old and load-bearing, treat the fix as major, or at least announce it like one.
- Raising minimum requirements (Node 18 β 20, dropping an OS) β breaking for the people on the old platform. Major.
The 0.x trap
Under the spec, 0.x.y means "anything may change at any time" β 0.x has
no compatibility promise at all. In practice, half the ecosystem treats
0.MINOR bumps as breaking and 0.x.PATCH as safe, and tooling
(npm's caret ranges, for one) encodes exactly that. Two rules of thumb:
- If you're on 0.x and people are using your thing in production, behave as if the minor number were major: announce 0.7 β 0.8 breakage the same way you'd announce 2.0.
- Don't camp on 0.x for years out of modesty. If strangers depend on it, it's 1.0 whether you've blessed it or not β tagging 1.0.0 just makes your promises legible.
Pre-releases and build metadata
A hyphen suffix marks a pre-release: 2.0.0-beta.1, 2.0.0-rc.2.
Pre-releases rank below the release they precede and carry no stability promise β
they exist so early adopters can opt in. Ship your big migration as an
-rc first; your bravest users will find the sharp edges before everyone else
hits them. (A +build.20260726 suffix is ignored for ordering entirely β it's
a note to yourself, not a signal to users.) Writing updates for those pre-release readers is
its own craft β see beta and early-access release
notes.
When semver is the wrong tool
Semver is a contract for things people build on: libraries, APIs, CLIs, plugins, self-hosted software people choose when to upgrade (release notes for CLIs and libraries covers writing for exactly those readers). It is mostly noise for things people log into. A SaaS app deploys continuously; users can't pin the old version, so "2.5.0" tells them nothing actionable. For products like that:
- Run a dated changelog instead β a stream of "what changed, when" entries tagged new / improved / fix. The date does the job the version number was doing. (Some products date the version itself β see CalVer vs SemVer.)
- Keep semver where a contract still exists: your public API can be
versioned (
/v1/,/v2/) even while the app above it ships daily. - When you do break the API, the version bump is not the announcement β the announcement is the announcement. See how to announce breaking changes.
Semver and your changelog, together
The two conventions are designed to pair: one Keep a Changelog section per version, breaking changes listed first, and the version number telling readers how carefully to read. If your release flow tags versions in git, your changelog can write itself β the tag, the release notes, and the public changelog entry should all come from the same step, or they'll drift.
Quick reference
Did anything that worked before stop working? β MAJOR Did you only add or fix things? β¦ added something new β MINOR β¦ fixed/optimized, no interface change β PATCH On 0.x with real users? β treat MINOR as MAJOR Product is a SaaS, not a dependency? β dated changelog, semver the API only
Wakelog is a free hosted changelog built for exactly this workflow: post an entry from the
same script that tags the release (git tag v2.5.0 && wakelog post --from-git),
or mirror GitHub/GitLab releases automatically. Dated stream, tags, RSS, and a widget β no
version-number theater required.
Start a free changelog Next: announcing breaking changes β
Related guides
- CalVer vs SemVer: how to pick a versioning scheme
What CalVer and SemVer each promise, which one fits your project, hybrid schemes β and what the choice means for your changelog. - Release names and version codenames: when a release needs a name (and when it doesnβt)
A version number is a compatibility statement; a name is a communication device β and most releases only need the first. What Ubuntu, Android, and Windows teach about naming schemes, why the number must stay canonical everywhere, and how to retire a codename without leaving your docs bilingual. - Alpha, beta, RC, GA: what release stages actually promise
Alpha, beta, RC, GA, canary, nightly, preview, early access β the industry has a zoo of words for “not quite done,” and every one of them is a promise someone will hold you to. What each stage actually commits you to, and how to announce the transitions.
Last updated 2026-07-28 Β· All guides