A semantic version comparator settles the question that dependency resolvers answer thousands of times a day: given two version strings, which one is newer? For plain releases the answer is obvious. For anything involving pre-release identifiers, numeric versus alphanumeric segments, or build metadata, the rules are precise, non-obvious, and routinely misremembered.
This tool applies the ordering rules from the Semantic Versioning specification and shows its working — which field decided the comparison, and why the fields before it were ties. Arb Digital added it to the free developer toolset for the moments when a package manager picks a version you did not expect and you need to know whether it is a bug or the spec working as designed.
What This Semantic Version Comparator Does
Enter two version strings and the tool parses each into its five parts: major, minor, patch, an optional pre-release, and optional build metadata. It validates both against the official grammar, ranks them, and reports which has higher precedence along with a plain-English explanation of the deciding field.
Beyond the raw comparison it answers three questions that matter when reading a dependency file. The change level tells you whether the difference is a major, minor, or patch step. The breaking-change indicator follows directly from that, because a major increment is precisely the signal that backwards compatibility was not preserved. And the two range checks show whether the common caret and tilde ranges written against version A would actually permit version B to be installed — the mechanism behind most "why did my build change?" incidents.
How to Use It
- Enter the two versions. Copy them straight from a lockfile, a changelog, or a release page. A leading
vis tolerated. - Read the headline. The result panel names the version with higher precedence, or states that the two are equal.
- Check the change level. Major, minor, and patch each carry a different promise about compatibility.
- Look at the range results. These show whether a caret or tilde constraint pinned to version A would have installed version B.
- Copy the reasoning into a pull request or an incident note when you need to justify a version decision to someone else.
The Formula / How It's Calculated
The rules come from the Semantic Versioning specification. A version is MAJOR.MINOR.PATCH, each a non-negative integer with no leading zeros, optionally followed by a hyphen and a pre-release identifier, optionally followed by a plus sign and build metadata.
Precedence is determined by comparing major, minor, and patch numerically, in that order, stopping at the first difference. So 2.0.0 outranks 1.9.3 on the major field alone, and the minor and patch numbers are never even consulted — 1.9.3 having a much larger minor number is irrelevant, because comparison is field by field and not a decimal number.
If all three numbers are equal, a version with a pre-release identifier has lower precedence than the same version without one. 1.0.0-alpha comes before 1.0.0. That single rule is the one most often reversed in people's heads, and it is the reason a release candidate never accidentally outranks the final release it precedes.
Build metadata is excluded from precedence entirely. 1.0.0+build.5 and 1.0.0+build.9 have exactly equal precedence, and a resolver is free to pick either.
How Pre-Release Identifiers Are Ordered
When two versions share the same major, minor, and patch and both carry a pre-release, the pre-release is split on dots and compared segment by segment. Each segment is classified as numeric or alphanumeric, and four rules apply in order.
Numeric segments are compared as numbers, so alpha.9 comes before alpha.10. That is the opposite of a string comparison, which would put 10 before 9, and it is why the specification bothers to make the distinction. Alphanumeric segments are compared as ASCII text, so alpha precedes beta precedes rc — an ordering that works purely because those three words happen to be alphabetical, not because the spec knows what they mean.
When one segment is numeric and the other is not, the numeric one has lower precedence. And when one identifier is a prefix of the other, the one with more segments wins: 1.0.0-alpha is lower than 1.0.0-alpha.1. The canonical ordering from the specification runs 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-alpha.beta, 1.0.0-beta, 1.0.0-beta.2, 1.0.0-beta.11, 1.0.0-rc.1, 1.0.0 — and reading it once with those four rules in mind makes the logic stick.
Why Caret and Tilde Ranges Behave Differently Below 1.0.0
A caret range means "compatible with", and it is defined by the leftmost non-zero field rather than by the major number alone. For ^1.2.3 the range permits anything from 1.2.3 up to but excluding 2.0.0. For ^0.2.3 it permits 0.2.3 up to but excluding 0.3.0, because when the major is zero the minor field is treated as the breaking-change field. For ^0.0.3 it permits only 0.0.3 up to but excluding 0.0.4.
This is why pinning to a caret range on a pre-1.0 dependency gives you far less room than the same syntax on a stable one, and why so many teams are surprised by how tightly a 0.x dependency is constrained. A tilde range is simpler: ~1.2.3 allows patch updates within 1.2, stopping before 1.3.0. Both operators are documented in the npm package.json reference, and the two range checks in the result panel apply exactly these rules to the versions you entered.
One further subtlety trips up almost everyone: pre-release versions do not satisfy a range unless the range itself mentions a pre-release at the same major, minor, and patch. ^1.0.0 will not install 1.5.0-beta.1, even though 1.5.0-beta.1 sits numerically inside the range, because opting into pre-release code is treated as something you must ask for explicitly.
What a Major Version Bump Actually Promises
Semantic versioning is a contract about the public API, not about the size of the change. A major bump says a backwards-incompatible change was made. A minor bump says functionality was added in a backwards-compatible way. A patch bump says only backwards-compatible fixes were included. A large internal refactor that changes nothing about the public interface is, correctly, a patch or minor release.
The contract only holds if the publisher follows it, and plenty do not. Some projects treat major versions as marketing milestones. Others ship breaking changes in a minor release by accident. A version number tells you what the maintainer intended to signal, which is useful information, but it is never a substitute for reading the changelog before upgrading anything that matters.
The specification also treats 0.y.z as explicitly unstable: anything may change at any time, and there is no compatibility promise at all. Version 1.0.0 is the point at which the API is declared stable and the rules start to bind.
Where Version Strings Are Not Semver At All
Many ecosystems use version schemes that look similar and rank differently. Calendar versioning uses the date — 2026.08.1 — which sorts correctly by these rules only by coincidence. Python packaging defines its own ordering with epochs and post-releases. Linux distributions use their own comparison algorithms with concepts semver has no equivalent for.
If a string fails to parse here, that does not necessarily mean it is invalid in its own ecosystem. It means it is not a semantic version, and semver ordering rules should not be applied to it. Common near-misses include a two-part version like 1.2, leading zeros such as 1.02.0, and four-part versions like 1.2.3.4, none of which the grammar permits.
Comparing Versions in a Lockfile or Deployment Check
The reasoning output is designed to be pasted into a review. When an automated dependency update opens a pull request, the useful summary is not just the two version strings but the change level and whether the compatibility promise was preserved. A patch step with no pre-release is a low-risk read; a major step deserves a changelog review; a pre-release entering a production dependency deserves a conversation.
The same logic applies to deployment guards. If your release process compares the version being deployed against the version currently running, that comparison has to implement precedence properly — including the pre-release rule — or a hotfix build tagged as a release candidate will be judged newer than the stable release it was meant to follow.
Arb Digital's web development team sets up dependency policies, release versioning, and deployment checks so upgrades are deliberate rather than accidental.
Web Development Services Talk to Arb DigitalCommon Mistakes to Avoid
- Reading a version as a decimal number. 1.10.0 is newer than 1.9.0, because minor is an integer field and not a fraction.
- Assuming a pre-release outranks the plain release. 1.0.0-rc.1 comes before 1.0.0, never after it.
- Using build metadata to publish a newer version. It is ignored in precedence, so the two versions rank as equal.
- Expecting a caret range on a 0.x package to allow minor updates. Below 1.0.0 the minor field acts as the breaking-change field.
- Trusting the number instead of the changelog. The version records what the maintainer intended to signal, not what actually changed.
Related Free Tools From Arb Digital
Compare release notes side by side with the diff checker, validate a manifest with the JSON validator or tidy one with the JSON formatter, test a version-matching pattern in the regex tester, and convert a build timestamp with the Unix timestamp converter. Everything else is in the free online tools hub.
Frequently Asked Questions
Yes. Major, minor, and patch are compared as separate integers, not as decimal places, so 10 is greater than 9 in the minor field.
Before. A version carrying a pre-release identifier always has lower precedence than the same major, minor, and patch without one.
No. Everything after the plus sign is ignored for precedence, so two versions differing only in build metadata are considered equal.
They are split on dots and compared segment by segment. Numeric segments compare as numbers, alphanumeric segments compare as ASCII text, numeric ranks below alphanumeric, and more segments outrank fewer when the rest matches.
It allows changes that do not modify the leftmost non-zero field. For 1.2.3 that means anything below 2.0.0, but for 0.2.3 it means anything below 0.3.0.
Pre-release versions only satisfy a range when the range itself specifies a pre-release at the same major, minor, and patch. Opting into pre-release code has to be explicit.
No. The specification requires all three numeric fields, so a two-part version fails to parse and semver ordering rules should not be applied to it.
Precedence here follows the Semantic Versioning specification. Individual package managers may add their own resolution behaviour on top of it.