Loading Semantic Version Comparator…
1.0.0-rc.1 < 1.0.0
1.0.0 is newer than 1.0.0-rc.1, on prerelease precedence.
1.0.0-alpha1.0.0-alpha.11.0.0-alpha.beta1.0.0-beta.21.0.0-beta.111.0.0-rc.1first1.0.0secondCaret, tilde, wildcards, explicit bounds, or two sets joined by ||.
Satisfied
^1.2.3 means >=1.2.3 <2.0.0
Caret on a 1.x release: minor and patch updates allowed.
Caret on 0.x: patch updates only.
Tilde: patch updates only.
An explicit pair of bounds.
A wildcard patch.
A prerelease sorts BELOW the release it precedes, so 1.0.0-rc.1 is older than 1.0.0. Within the tag, dot-separated identifiers are compared one at a time: numeric ones numerically, so beta.11 beats beta.2, and anything containing a letter as ASCII text. Build metadata after a + is ignored entirely.
Caret is not one rule but two. On a 1.x or later release it allows minor and patch updates, so ^1.2.3 accepts 1.9.0. Below 1.0.0 it treats a minor bump as breaking, so ^0.2.3 stops at 0.2.x and ^0.0.3 allows nothing but 0.0.3 itself.
Semantic versioning gives a release three parts — major, minor and patch — and a rule for each: a major bump breaks something, a minor bump adds something compatibly, a patch bump fixes something. Comparing two of them is arithmetic on each part in turn, which is why 1.2.10 is newer than 1.2.9 and 10.0.0 is newer than 2.0.0. Sort the same strings as text and you get the opposite answer for both, which is how a deployment pipeline ends up shipping backwards.
This page does two jobs. It puts two versions in order and says which part decided it, and it tests whether a version falls inside a range, expanding shorthand such as a caret into the two bounds it really means.
A tag after a hyphen makes a version LOWER than the plain release it precedes, so 1.0.0-rc.1 is older than 1.0.0. This is the rule people get backwards, because a release candidate feels like an addition rather than a subtraction.
Within the tag, dot-separated identifiers are compared one at a time. Numeric identifiers compare numerically, so beta.11 comes after beta.2 — text sorting would put 11 first. Identifiers containing a letter compare as ASCII, which puts uppercase before lowercase and makes 1.0.0-Beta lower than 1.0.0-beta. A numeric identifier always loses to an alphanumeric one, and when every shared identifier matches, the shorter list is the lower version.
Put together, the spec ordering runs 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-alpha.beta, 1.0.0-beta.2, 1.0.0-beta.11, 1.0.0-rc.1, then 1.0.0. Anything after a plus sign is build metadata and takes no part in this at all: 1.0.0+exp.sha.5114f85 and 1.0.0+exp.sha.aaaaaaa have equal precedence, so metadata is no way to mark one build as newer than another.
On a release of 1.0.0 or later, a caret allows anything up to the next major version: ^1.2.3 expands to at least 1.2.3 and below 2.0.0, so it accepts 1.9.9. Below 1.0.0 the same caret treats a minor bump as breaking, because that is where breaking changes live during early development. So ^0.2.3 expands to at least 0.2.3 and below 0.3.0, and refuses 0.3.0 outright, while ^0.0.3 permits nothing but 0.0.3.
Tilde is stricter and steadier: ~1.2.3 allows patches only, up to but not including 1.3.0. Given a partial version it widens by one level, so ~1.2 is the same window and ~1 covers all of 1.x. A wildcard behaves like the equivalent tilde — 1.2.x and ~1.2.0 are identical ranges — and two bounds written out, such as at least 1.0.0 and below 2.0.0, mean exactly what they say.
This asymmetry is the practical reason a library sitting at 0.x gets patch updates and nothing else. Publishing 1.0.0 is partly a statement that consumers may now take your minor releases automatically.
A range of at least 1.0.0 looks like it should accept 2.0.0-beta.1, since the beta sorts above 1.0.0. It does not, and the rule that stops it is deliberate: a prerelease satisfies a range only when some bound in the same set names a prerelease of the identical major, minor and patch. So 1.2.4-beta.1 satisfies a range from 1.2.4-alpha up to 1.3.0, but 1.2.5-beta.1 does not, and no ordinary caret range will ever pull an untested beta into a build.
Older. The prerelease tag lowers it, so 1.0.0-rc.1 sits immediately below 1.0.0 in precedence. That is exactly what you want from a release candidate: publishing the final 1.0.0 supersedes it automatically, with no extra version number needed.
Because a caret below 1.0.0 stops at the next minor version rather than the next major one. ^0.2.3 means at least 0.2.3 and below 0.3.0. If you want the newer minor you have to say so, by changing the range to ^0.3.0 or to a pair of explicit bounds.
Not for ordering or for range matching — the spec says build metadata is ignored in precedence, and two versions differing only there rank equal. It is still useful as a label for a commit hash or a build number, but you cannot use it to publish a fix.
Treat the minor position as your major one: bump 0.2.x to 0.3.0 when you break something, and to 0.2.4 when you do not. Everyone consuming your package with a caret will get patches only, which is the behaviour the convention assumes.
Anything a reasonable consumer could be relying on: a removed or renamed export, a changed argument order, a narrowed input, a new required option, or a different error type. Dropping support for an old runtime counts too, which is why upgrading a minimum Node version usually calls for a major release.