🏆 US-Registered Digital Marketing Agency Trusted by 200+ brands · USA · UK · Canada · AUS
Advertisement
Advertisement
DEVELOPER

Semantic Version Comparator — which version wins, and why

Compare two semver strings and see the exact precedence reasoning, including pre-release ordering and range matching.

A leading v is accepted and ignored, as most tooling does.
Try pre-release and build metadata to see how each is treated.
Field-by-field comparison in the order the specification requires, stopping at the first difference.
Higher precedence
 
Change level
Breaking change
Caret range ^A allows B
Tilde range ~A allows B
Tip: build metadata after a plus sign is ignored entirely when ranking versions. Two releases that differ only in build metadata have equal precedence, which means you cannot use it to publish a "newer" version.
Advertisement

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

  1. Enter the two versions. Copy them straight from a lockfile, a changelog, or a release page. A leading v is tolerated.
  2. Read the headline. The result panel names the version with higher precedence, or states that the two are equal.
  3. Check the change level. Major, minor, and patch each carry a different promise about compatibility.
  4. Look at the range results. These show whether a caret or tilde constraint pinned to version A would have installed version B.
  5. 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.

Advertisement

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.

Shipping software you need to keep stable through upgrades?

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 Digital

Common 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

Is 1.10.0 newer than 1.9.0?

Yes. Major, minor, and patch are compared as separate integers, not as decimal places, so 10 is greater than 9 in the minor field.

Does 1.0.0-rc.1 come before or after 1.0.0?

Before. A version carrying a pre-release identifier always has lower precedence than the same major, minor, and patch without one.

Is build metadata used when ranking versions?

No. Everything after the plus sign is ignored for precedence, so two versions differing only in build metadata are considered equal.

How are pre-release identifiers ordered?

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.

What does a caret range allow?

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.

Why will my caret range not install a pre-release?

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.

Is 1.2 a valid semantic version?

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.

Advertisement
Advertisement
Arb Digital assistant

👋 Hey! Want to grow your business? Ask me anything — a free marketing proposal is on the table!