Skip to content
ToolBoxGeniehome

Semantic Version Comparator

Developer Tools · Added

Semantic versions do not compare as strings, and the places they differ are the places people get caught: a pre-release sorts below the release it precedes, numeric identifiers compare as numbers, and build metadata is ignored entirely. This applies the rules as written.

What do you want to do?
Try:

Result

Result

1.0.0-rc.1 is lower

The same release, at a different pre-release stage. Remember that a pre-release sorts below the final release, not above it.

In order
1.0.0-rc.1 < 1.0.0
A — major.minor.patch
1.0.0
A — pre-release
rc.1
A — build metadata
none
B — major.minor.patch
1.0.0
B — pre-release
none
B — build metadata
none

Next releases from 1.0.0-rc.1

Major
2.0.0
Minor
1.1.0
Patch
1.0.1

Three rules decide every comparison. A pre-release sorts below the release it precedes, so 1.0.0-rc.1 comes before 1.0.0. Numeric pre-release identifiers compare as numbers, so alpha.9 is below alpha.10 — as strings the order would reverse. And build metadata after a plus sign is ignored entirely, so two versions differing only there have equal precedence without being the same string.

How to use the semantic version comparator

  1. 1Pick what you are doing: comparing two versions, testing a range, or sorting a list.
  2. 2Enter the versions. A leading v is accepted and ignored.
  3. 3Read the verdict and the breakdown beneath it.
  4. 4For a range, check the lowest and highest versions it accepts — that is usually the answer you wanted.

Examples

A release candidate

Input
1.0.0-rc.1 against 1.0.0
Result
1.0.0-rc.1 is lower — a pre-release comes before the release it precedes

A caret range

Input
Does 1.5.0 satisfy ^1.2.3?
Result
Yes — the range accepts anything from 1.2.3 up to but not including 2.0.0

About the semantic version comparator

What the three numbers promise

A major bump says something that used to work no longer does. A minor bump says something was added and everything that worked still works. A patch bump says a bug was fixed and nothing else changed. That is the whole contract, and its value is entirely in being kept — a project that ships a breaking change in a patch release has not made a versioning mistake so much as broken a promise its users automated against.

This is why the zero major version exists as an explicit escape hatch. Below 1.0.0 the contract is suspended, and tooling knows it: the caret range tightens automatically rather than trusting a stability that was never claimed.

Precedence order is not release order

Sorting a list here gives precedence order, which is what a resolver uses, and it is frequently not the order things were published. A 1.0.0 release ships after its own release candidates and sorts above them. A security patch to an old major version can be published years after a newer major and still sorts below it.

That distinction matters when reading a changelog against a version list. The list says which version is newer in the specification's sense; only the dates say which was released later.

Frequently asked questions

Why does 1.0.0-alpha.10 sort above 1.0.0-alpha.9?
Because the specification says a pre-release identifier made only of digits compares numerically, and 10 is greater than 9. Compared as text the order inverts, since the character 1 sorts before 9 — which is exactly the bug this rule exists to prevent, and exactly what a naive string sort produces.
What does build metadata do?
Nothing, for ordering. The specification states that everything after a plus sign is ignored when determining precedence, so 1.0.0+build.1 and 1.0.0+build.2 have equal precedence while being different strings. Package managers rely on that: two builds of the same version are the same version.
How do caret and tilde differ?
The caret allows minor and patch to move, so ^1.2.3 accepts anything below 2.0.0. The tilde allows patch only, so ~1.2.3 stops below 1.3.0. Neither is part of semver itself — both come from npm — and below version 1.0.0 the caret tightens to behave like a tilde, because a zero major version means the interface is not stable yet.
Why does my pre-release fail a range it looks like it should pass?
Because a pre-release only satisfies a range when the range itself names a pre-release of the same major, minor and patch. It is npm's rule rather than the specification's, and it exists so that ^1.0.0 cannot quietly install 2.0.0-alpha.1 — a breaking change arriving through a range written specifically to avoid one.