Semantic Version Range Evaluator

Type a range expression and a list of versions. The panel reports which candidates satisfy the range, which are excluded, and which one a resolver would select. Versions can be separated by spaces, commas or newlines.

Recognised forms: 1.2.3, =1.2, >1.2, >=1.2 <2.0, 1.x, 1.2.*, *, ~1.2.3, ^1.2.3, 1.2.3 - 2.3.4, and unions written with ||. Space between comparators means and.

Why a range is not a wish

A range is a promise you make to a resolver about which future releases you will accept without looking at them. ^1.2.3 says: any release up to but not including the next major is acceptable, sight unseen. That is a delegation of review authority to whoever publishes the package, on the strength of a version number they chose themselves.

The number is a claim, not a guarantee. Nothing in the specification, and nothing in any registry, verifies that a minor release is actually backward compatible. The contract is social. What the resolver enforces is only the arithmetic.

Caret gets narrower below one

The rule most often misread is caret behaviour under 0.x, and the evaluator above makes it visible. Above 1.0.0, caret allows minor and patch movement: ^1.2.3 reaches 1.9.9. Below it, the leftmost non-zero part is treated as the breaking position instead:

This is deliberate. Pre-1.0 releases are declared unstable by the specification itself, so the resolver assumes any movement can break you. Teams that pin ^0.x expecting the same latitude they get from ^1.x are getting a much tighter constraint than they think — which is usually the safer surprise, but a surprise nonetheless.

Pre-releases are opt-in territory

A pre-release sorts below its release: 1.0.0-rc.1 is lower than 1.0.0. Within a pre-release, identifiers are compared field by field — numeric fields numerically, alphanumeric fields in ASCII order, with numeric ranking below alphanumeric, and a longer identifier list outranking a shorter one where the shared fields are equal. That is what produces the published ordering 1.0.0-alpha1.0.0-alpha.11.0.0-alpha.beta1.0.0-beta1.0.0-beta.21.0.0-beta.111.0.0-rc.11.0.0, and it is why beta.11 beats beta.2 rather than losing to it on string comparison.

The rule that catches people is the one about matching. A candidate carrying a pre-release only satisfies a range when the range itself names a pre-release on the same major.minor.patch. So ^1.2.3 does not pick up 1.3.0-rc.1, even though 1.3.0-rc.1 sits comfortably between the bounds. You have to ask for pre-release territory explicitly, by writing a range that mentions one.

Try ^1.2.3-alpha.1 against 1.2.3-alpha.2, 1.2.3-beta, 1.2.3 and 1.2.4-alpha.1. The first three match; the last does not, because its major.minor.patch is not the one the range named.

What build metadata does

Everything after + is ignored for ordering. 1.0.0+build.7 and 1.0.0+build.9 have identical precedence — they are the same version as far as resolution is concerned. If two of your artefacts differ only in build metadata, no range expression can prefer one over the other, and any tool that appears to choose is choosing by something other than precedence.

On the self-test

The line under the panel is not decoration. The evaluator checks itself against a fixed set of worked cases every time the page loads — caret above and below 1.0.0, tilde with two and three parts, x-ranges, hyphen ranges, unions, partial comparators, pre-release exclusion, and the specification’s own ordering chain. If any case fails, the tool switches itself off and says so rather than returning an answer you might paste into a manifest.

Two known limits, stated rather than hidden: the parser is lenient about leading zeros in numeric identifiers, which the specification forbids, and it does not implement registry-specific extensions such as tag, URL or workspace specifiers. Both are validation concerns rather than precedence concerns.