Developer Utilities

SemVer Comparator

Strictly validate, compare, and sort Semantic Versioning 2.0.0 versions.

SemVer 2.0.0
Strict validation and precedence comparison, including prerelease identifiers.
Version B has higher precedence
VersionMajorMinorPatchPrereleaseBuild
1.8.0-beta.2180beta.2—
1.8.0180——
Sort a version list
One version per line; invalid entries are excluded from the result.
Sorted result
2.0.0 2.0.0-rc.1 1.8.0 1.8.0-beta.2 1.7.12

SemVer Comparison

Strictly validate, compare, and sort Semantic Versioning 2.0.0 versions, including numeric and alphanumeric prerelease identifiers.

Precedence

  • Major, minor, and patch are compared in order
  • A release has higher precedence than a prerelease with the same core version
  • Build metadata does not affect precedence

Compares and sorts Semantic Versioning 2.0.0 strings by the specification precedence rules instead of by character order. Enter two versions to see which one outranks the other, or paste a whole list to sort it, with major, minor, patch, prerelease, and build fields shown per entry.

The grammar an input has to match in one piece

The whole string must match one pattern: three dot-separated numbers, each written as 0|[1-9]\d*, then an optional - prerelease and an optional + build, where identifiers use only [0-9A-Za-z-] and are joined by dots. Anything else fails outright: v1.2.3, 1.2, 1.2.3.4, 01.2.3, =1.2.3. Only leading and trailing whitespace is trimmed first. One rule sits outside the pattern: a prerelease identifier consisting solely of digits may not carry a leading zero, so 1.0.0-01 is rejected even though every character is legal. That is specification rule 9, and it is the error hit most often when tags are generated from a zero-padded build counter.

How precedence is actually decided

Major, minor, and patch compare as numbers, then the prerelease field decides, then nothing: build metadata never affects order, so 1.0.0+a and 1.0.0+b tie and the tool says so. A version without prerelease outranks every prerelease of the same core. Prerelease identifiers compare one at a time: two numeric identifiers compare as integers, a numeric identifier always loses to an alphanumeric one, alphanumeric ones compare as ASCII, and when every compared identifier matches, the shorter set is lower, so 1.0.0-beta ranks below 1.0.0-beta.2. Fields are held as BigInt, keeping 9007199254740993.0.0 above 9007199254740992.0.0, a distinction plain JavaScript numbers lose past 2^53.

Precedence, not range resolution

This answers which version is newer, not whether a version satisfies a constraint. Range syntax such as ^1.6.0, ~1.8, x-ranges, comparator sets, and || unions is rejected as an invalid version, and no dependency tree is resolved here. The npm installer also enforces a policy that the specification never states: a prerelease matches a range only when some comparator inside that range carries a prerelease on the same major.minor.patch. A version this tool ranks above 1.8.0 can therefore still be skipped during install. Order tags, changelog headings, and image labels here; judge upgrade eligibility with a real resolver.

Worked example

Sorting a prerelease line-up, oldest first

Input
1.0.0-beta.2
1.0.0-rc.1
1.0.0
1.0.0-beta.11
1.0.0+build.7
Output
1.0.0-beta.2
1.0.0-beta.11
1.0.0-rc.1
1.0.0
1.0.0+build.7

Numeric identifiers compare as integers, so 1.0.0-beta.11 lands after 1.0.0-beta.2; character order would put beta.11 first. The release 1.0.0 outranks both prereleases, and 1.0.0+build.7 ties with it because build metadata is ignored, so the stable sort leaves those two in input order.

Limits and pitfalls

  • A leading zero on a purely numeric prerelease identifier is refused, so 1.0.0-01 or 1.2.0-beta.007 produced by a padded build counter must be rewritten before it parses.
  • There is no range or constraint evaluation: caret, tilde, wildcard, comparator, and union expressions all fail the version pattern, so nothing tells you if a version satisfies a dependency spec.
  • Build metadata is parsed and displayed but never ordered, so two rows differing only in +build compare equal and their relative position in the sorted output follows input order.
  • Lines that fail validation are dropped from the sorted output and only listed in an error strip, so copying the result silently loses them; duplicate versions are kept, not deduplicated.
  • Prefixes and decorations are not stripped: v1.2.3, release-1.2.3, or a trailing newline inside a value stay invalid unless trimmed to the bare three-part version.

Related tools

Ranking versions on this page, or handing the question to a resolver

What you are trying to settleThis page (precedence only)The thing that actually answers it
Whether 1.7.0 satisfies ^1.6.0Not decidable here. The caret spelling does not match the version pattern, so the input is reported as an invalid version rather than as unsatisfied — two very different answers if you read the strip too quickly.Install node-semver and call satisfies("1.7.0", "^1.6.0"): that is the same library npm consults when it walks a dependency tree, and it also knows the prerelease-matching policy the specification leaves out.
Ordering the five prerelease tags you just pushedPaste them one per line and read the digits straight off: identifiers are compared one by one as BigInt, build suffixes are ignored, and the result is a plain list you can drop into a changelog draft.git tag --sort=-v:refname takes the names from the repository instead of your clipboard, so nothing gets retyped. It sorts whatever strings it finds without validating them, and it never says two tags tie.
Tags that carry a v prefixThe prefix is not stripped: v1.4.0 is refused and appears only in the invalid strip, so a batch that was supposed to be five rows quietly comes back with two.Clean the list before it reaches the page with sed "s/^v//", or skip sorting altogether when all you need is the single newest tag — git describe --tags --abbrev=0 answers that in one line.
Validating a few hundred tags in CIAny number of lines can be pasted, but the verdict stays on the screen: nothing here can make a pipeline job fail, so a bad tag only gets noticed if someone is looking.Keep the check in Node — lines.filter(l => !semver.valid(l)) followed by process.exit(1) — so the offending tag names land in the build log and the release stops before publishing.
One question: which of these two builds is newerTwo input boxes and a single sentence, including the explicit "same precedence" verdict when the only difference is +build — worth having precisely because a character diff would wrongly call them different.git only knows reachability: git describe --tags --abbrev=0 returns the nearest tag on the current history, so a maintenance branch that received backports reports an older version than the service actually ships.
Versions copied out of a README or an old changelogStrict only: 1.2, =1.2.3 and 1.2.3.4 are hard errors, because all three numeric parts are mandatory and nothing else may surround them.semver.coerce("1.2") pads the missing part to 1.2.0, and loose parsing accepts zero-padded numbers. Reach for it when repairing historical data; keep strict checking for the release you are about to publish.

SemVer 2.0.0 input shapes, field by field

Where the rule sitsWhat this page acceptsWhat it refuses, or what surprises people
major / minor / patchEach part matches 0|[1-9]\d* and is held as BigInt, so a twenty-digit major still compares exactly instead of drifting past 2^53.01.2.3, 1.2, 1.2.3.4 and 1.2.3v all fail the one anchored pattern — there is no partial match and no salvage.
prerelease separatorA single - directly after patch, followed by at least one identifier. A hyphen may itself begin an identifier, so 1.0.0--rc parses.1.0.0- leaves the section empty and fails; 1.0.0~rc.1 uses a character the grammar never allows as a separator.
prerelease identifiersDot-separated runs of [0-9A-Za-z-], at least one character each, any number of them.1.0.0-rc_1 (underscore) and 1.0.0-rc..1 (an empty element between two dots) are both rejected.
build metadataSame character set after +, and its numeric identifiers may be zero-padded: 1.0.0+001 and 1.0.0+build.01 both pass.1.0.0+ with nothing behind the sign fails. The asymmetry trips people up: +001 is fine while -001 is refused as a zero-padded numeric prerelease identifier.
surrounding spaceThe whole string is trim()-ed before matching, so 1.0.0 is the same version and the table shows the trimmed spelling.Space inside the version (1. 0.0) or a tab between characters is not trimmed in the middle; the match simply fails.
alphanumeric identifiersCompared by UTF-16 code unit, which over this character set is plain ASCII: hyphen 0x2D < digits 0x30–0x39 < uppercase 0x41–0x5A < lowercase 0x61–0x7A.1.0.0-Alpha ranks below 1.0.0-alpha, and 1.0.0--rc below 1.0.0-rc, because the leading hyphen is the lowest code unit available.
numeric identifiersTwo digit-only identifiers compare as integers through BigInt, so 10 beats 9; any digit-only identifier ranks below any identifier containing a letter.1.0.0-9 ranks below 1.0.0-alpha — the reverse of what character comparison would produce.
the sorting listOne version per line, LF or CRLF; blank and whitespace-only lines disappear silently, so trailing newlines cost nothing.Duplicates stay as separate rows, and invalid lines are removed from the output and only echoed in the error strip — copying the result loses them without a warning.

Every row is enforced by the same anchored pattern and identifier comparison the panel runs, so you can confirm any of them by typing both spellings into Version A and Version B. The last rows explain a list that looks unsorted: build metadata never participates, and equal versions keep input order in both directions, so 1.0.0+build.9 stays above 1.0.0+build.7 even in the newest-first view.

Frequently Asked Questions

What is the difference between ^ and ~ in semver?
~1.2.3 allows patch changes (>=1.2.3 <1.3.0); ^1.2.3 allows minor and below (>=1.2.3 <2.0.0). For 0.x versions ^0.2.3 only allows patches — during 0.x the minor acts as the breaking-change slot. npm saves ^ by default.
Does a prerelease (1.0.0-beta.1) outrank the release?
No: 1.0.0 outranks every 1.0.0-x prerelease. Prerelease identifiers compare lexicographically (alpha < beta < rc). Build metadata (+build.1) does not affect precedence at all — 1.0.0+a equals 1.0.0+b, a common misconception when deciding whether to republish.
When should I bump the major version?
Whenever existing users can break: removed or re-signatured exports, behavior changes, raised environment requirements. When unsure whether a change is breaking, treat it as breaking — semver’s value is trustworthy upgrades, and an accidental minor bump costs far more than an extra major.

Content reviewed: