SemVer 2.0.0: major vs minor vs patch, prereleases, and npm bumps

Published: 2026-09-05

How Semantic Versioning 2.0.0 defines MAJOR.MINOR.PATCH, prerelease and build metadata, precedence rules, and npm-style major/minor/patch bumps—including how matching prereleases graduate.

Semantic Versioning (SemVer) 2.0.0 is a shared contract for software version numbers: three non-negative integers, optional prerelease labels, optional build metadata, and a clear rule for which version is “greater.” When teams follow it, npm install, changelogs, and dependency ranges become predictable instead of tribal knowledge.

This guide walks through the core fields, precedence, and npm-compatible bumps—then points you at a local calculator so you can parse and increment strings without pasting package versions into a random web form.

The shape: MAJOR.MINOR.PATCH

A SemVer string looks like:

1.4.2
1.4.2-alpha.1
1.4.2-rc.1+build.9
v2.0.0
Field Meaning in practice
MAJOR Incompatible API / public contract changes
MINOR Backward-compatible new features
PATCH Backward-compatible bug fixes

Rules that trip people up:

  • Exactly three numeric core parts (1.2 alone is not SemVer 2.0.0).
  • No leading zeros on core numbers (01.2.3 is invalid; 0.1.0 is fine).
  • An optional v / V prefix is common in git tags; tools often strip it for the canonical form MAJOR.MINOR.PATCH….

SemVer is about compatibility signaling, not calendar date or marketing. A “2.0” that only renames a CSS class still communicates a breaking change to dependents.

Prerelease: -alpha.1, -rc.2, and friends

Anything after a hyphen and before + is the prerelease:

2.0.0-alpha.1
2.0.0-beta
2.0.0-rc.2

Identifiers are dot-separated: letters, digits, and hyphens. Numeric identifiers must not have leading zeros (01 is invalid; 0 and 10 are fine).

Precedence: a release without a prerelease is greater than the same core with a prerelease:

1.0.0-rc.1  <  1.0.0

Among prereleases with the same MAJOR.MINOR.PATCH, compare identifiers left to right. Numeric identifiers compare as numbers; non-numeric compare as strings. A numeric identifier is always lower than a non-numeric one of equal position (1.0.0-1 < 1.0.0-alpha). A longer list wins only after all shared identifiers tie (1.0.0-alpha < 1.0.0-alpha.1).

Use prereleases when you need installable previews (next, beta channels) that sort below the final release of that version.

Build metadata: +… does not change order

After + comes build metadata (CI build ids, git SHAs, etc.):

1.0.0+20130313144700
1.0.0-beta+exp.sha.5114f85

Build metadata is part of the version string for identity and debugging, but must be ignored when comparing precedence. These are equal for ordering:

1.0.0+build.1   =   1.0.0+build.2   =   1.0.0

Many bump tools drop build metadata on increment so the next tag stays clean.

Major, minor, and patch bumps (stable releases)

Starting from a stable version (no prerelease):

Bump From 1.2.3 Typical intent
major 2.0.0 Breaking change
minor 1.3.0 Compatible feature (patch resets)
patch 1.2.4 Compatible fix

npm’s semver.inc (and LocalTools’ SemVer calculator) graduates a prerelease to the matching stable release when you bump at the “same” level, instead of always ticking the core number up again:

Current Bump Result Why
1.2.3-rc.1 patch 1.2.3 Clear prerelease; patch stays
1.2.0-rc.1 minor 1.2.0 Already on that minor; only prerelease left
1.2.3-rc.1 minor 1.3.0 Patch was non-zero → minor increments
2.0.0-rc.1 major 2.0.0 Already on that major with .0.0
1.2.3-rc.1 major 2.0.0 Not yet on N.0.0 → major increments

That graduation behavior matches what many release scripts expect when you ship the final 1.2.3 after 1.2.3-rc.*.

Prerelease bumps: prerelease, premajor, preminor, prepatch

Release type Idea
prerelease Bump the prerelease counter; if you were on a stable version, bump patch first then attach prerelease
prepatch Next patch, then attach prerelease (1.2.31.2.4-0 or 1.2.4-alpha.0)
preminor Next minor, patch 0, then prerelease
premajor Next major, minor/patch 0, then prerelease

An optional identifier (alpha, beta, rc) replaces or restarts the prerelease series:

  • 1.2.3 + prerelease with alpha1.2.4-alpha.0
  • 1.2.4-alpha.0 + prerelease with alpha1.2.4-alpha.1
  • Switching identifier (e.g. to beta) starts a new series for that label

Blank identifier usually means a numeric-only prerelease such as -0, -1, …

What SemVer does not cover

  • Ranges (^1.2.3, ~1.2.3, >=2 <3, ||) — how package managers select versions. Parsing and bumping a single string is separate from evaluating a range.
  • CalVer or marketing versions (2024.09, vNext) — different schemes.
  • Git describe output with commit counts (1.2.3-4-gabcdef) — not SemVer 2.0.0 unless you normalize it.

If your tool says ranges are out of scope, that is intentional: compare and bump first; let npm / pnpm resolve ranges in the lockfile.

A safe local workflow

  1. Paste the current version from package.json or a git tag (v1.4.2-rc.1).
  2. Confirm canonical core, prerelease, and build fields.
  3. Choose the bump that matches your changelog intent (breaking → major, feature → minor, fix → patch; use pre* for tagged previews).
  4. Compare two candidates when deciding whether a published tag is newer than what is installed—remember build metadata does not decide order.
  5. Copy the result into the release commit / tag.

All of that can run entirely in the browser so version strings from private packages never need to leave your machine. For the broader privacy model, see Why “local only” matters for developer tools.

Try it locally in your browser

Use the SemVer calculator to:

  • Parse strict SemVer 2.0.0 (optional v/V prefix stripped in the canonical form).
  • See major, minor, patch, prerelease, and build broken out.
  • Apply major / minor / patch / prerelease / premajor / preminor / prepatch bumps (npm-style; build metadata dropped on bump).
  • Compare two versions with correct precedence (build ignored; stable > prerelease).

Related reading

All learn articles