compare-versions and semver are both widely used npm packages for comparing software version strings, especially those following semantic versioning (SemVer). semver is a comprehensive, standards-compliant toolkit that implements the full SemVer specification (v2.0.0), offering validation, comparison, range matching, and manipulation utilities. compare-versions, by contrast, is a minimal, focused library designed specifically for comparing version strings — including non-standard formats like dates or build numbers — with an emphasis on simplicity and predictable ordering.
compare-versions vs semverWhen your frontend app needs to compare software versions — whether to show update prompts, enforce compatibility, or sort changelogs — picking the right library matters. Both compare-versions and semver solve this problem, but they take very different approaches. Let’s break down how they work, where they shine, and what trade-offs you’ll face.
compare-versions treats version comparison as a general-purpose string-sorting problem. It doesn’t assume your input follows any particular standard. It splits strings on dots, compares each segment numerically (falling back to string comparison if needed), and handles common prefixes like v automatically.
// compare-versions: works with almost anything
import compareVersions from 'compare-versions';
compareVersions('1.10.0', '1.2.0'); // returns 1 (1.10 > 1.2)
compareVersions('v2.0.0', '2.0.0'); // returns 0 (equal)
compareVersions('2023.10', '2023.9'); // returns 1
semver, on the other hand, strictly enforces the Semantic Versioning 2.0.0 spec. It will reject invalid SemVer strings and correctly interpret prereleases, build metadata, and numeric precedence as defined by the standard.
// semver: strict SemVer only
import semver from 'semver';
semver.compare('1.10.0', '1.2.0'); // returns 1
semver.compare('v2.0.0', '2.0.0'); // returns 0 (normalizes 'v')
semver.compare('2023.10', '2023.9'); // throws TypeError: Invalid Version
💡 Key insight:
compare-versionsprioritizes "just make it work";semverprioritizes "do it by the book."
compare-versions treats prerelease identifiers as plain strings and compares them lexicographically:
// compare-versions
compareVersions('1.0.0-alpha', '1.0.0-beta'); // returns -1
compareVersions('1.0.0-rc.1', '1.0.0-rc.10'); // returns 1 (because '1' > '10' as strings)
This can lead to incorrect ordering for numeric prerelease tags (like rc.10 vs rc.2).
semver correctly parses and compares prerelease identifiers per the SemVer spec — splitting on dots, comparing numerically where possible, and falling back to ASCII sort order:
// semver
semver.compare('1.0.0-alpha', '1.0.0-beta'); // returns -1
semver.compare('1.0.0-rc.1', '1.0.0-rc.10'); // returns -1 (1 < 10 numerically)
semver.compare('1.0.0-rc.2', '1.0.0-rc.10'); // returns -1
If you’re dealing with version-like strings that aren’t true SemVer — say, calendar versions (2023.10.05) or simplified formats (2.1) — compare-versions handles them gracefully:
// compare-versions
compareVersions('2.1', '2.10'); // returns -1 (2.1 < 2.10)
compareVersions('2023.10.5', '2023.10.15'); // returns -1
semver will throw an error unless you preprocess these into valid SemVer (e.g., 2.1.0):
// semver
semver.compare('2.1', '2.10'); // throws TypeError
// You must normalize first:
semver.compare(semver.coerce('2.1'), semver.coerce('2.10')); // returns -1
Note: semver.coerce() can help, but it’s lossy and may not always produce the expected result.
compare-versions exports a single function. That’s it. If you need sorting, you use it as a comparator:
// Sorting with compare-versions
const versions = ['1.10.0', '1.2.0', '2.0.0'];
versions.sort(compareVersions); // ['1.2.0', '1.10.0', '2.0.0']
semver provides a rich API beyond comparison:
semver.valid(v) – checks if a string is valid SemVersemver.satisfies(version, range) – tests if a version matches a range like ^1.2.3semver.inc(version, release) – increments a version (e.g., patch, minor)semver.prerelease(v) – extracts prerelease components// semver: advanced usage
semver.satisfies('1.2.3', '^1.0.0'); // true
semver.satisfies('2.0.0', '^1.0.0'); // false
semver.inc('1.2.3', 'minor'); // '1.3.0'
semver.valid('1.2'); // null (invalid)
semver.valid('1.2.3'); // '1.2.3'
If your app needs to check whether a user’s current version falls within a supported range (e.g., for feature flags or update eligibility), semver is the only practical choice.
compare-versions Winssemver Wins1.10 > 1.2).Switching from compare-versions to semver isn’t always drop-in. For example:
// This works in compare-versions
compareVersions('1.0', '1.0.0'); // returns 0
// But in semver, you must normalize:
semver.compare('1.0.0', '1.0.0'); // OK
semver.compare('1.0', '1.0.0'); // throws error
You’d need to wrap inputs with semver.coerce() — but be cautious:
semver.coerce('1.0'); // '1.0.0'
semver.coerce('2023.10'); // '2023.10.0'
semver.coerce('v1.2.3'); // '1.2.3'
However, coerce can produce unexpected results with malformed input (e.g., coerce('abc1.2.3def') → '1.2.3'), so use it only when you control or trust the input format.
| Feature | compare-versions | semver |
|---|---|---|
| Input Flexibility | ✅ Handles non-SemVer, partial versions | ❌ Strict SemVer only (unless coerced) |
| Prerelease Handling | ❌ Lexicographic (may misorder rc.10) | ✅ Spec-compliant numeric/string comparison |
| API Scope | 🔹 Single compare(a, b) function | 🔸 Full toolkit (validate, range, inc, etc.) |
| Use Case Fit | Lightweight comparison of mixed formats | Full SemVer compliance and advanced logic |
compare-versions if your goal is simple, forgiving comparison across unpredictable version formats — especially in UIs that display third-party version data.semver if you’re working in a SemVer-native environment (like package management, DevOps tooling, or internal version policies) and need correctness, validation, or range logic.In short: if you’re just sorting a list of version strings from an API that might include 2.1, v3.0.0-beta, and 2024.05, go with compare-versions. If you’re building a dependency resolver or update checker that must respect ^2.1.0 || >=3.0.0, semver is non-negotiable.
Choose compare-versions if you need a lightweight, zero-dependency utility that handles basic version comparisons across a wide variety of formats — including non-SemVer strings like '1.2', '2023.10.05', or even 'v1.0.0-beta'. It’s ideal for scenarios where you only need to sort or compare versions without requiring full SemVer compliance, validation, or advanced features like range matching. Its API is intentionally minimal: just one function that returns -1, 0, or 1.
Choose semver if your project strictly follows semantic versioning and you need robust, spec-compliant tooling beyond simple comparison — such as validating version strings, checking if a version satisfies a range (e.g., '^1.2.3'), incrementing versions, or parsing prerelease identifiers. It’s the de facto standard in the Node.js ecosystem and integrates deeply with tools like npm. Use it when correctness according to the SemVer spec is critical.
Compare semver version strings to find greater, equal or lesser. Runs in the browser as well as Node.js/React Native etc. Has no dependencies and is tiny.
Supports the full semver specification including versions with different number of digits like 1.0.0, 1.0, 1 and pre-releases like 1.0.0-alpha. Additionally supports the following variations:
1.0.x or 1.0.*.25.0.1364.126.v is ignored, e.g. v1.0 is interpreted as 1.0.1.01.1 is interpreted as 1.1.1.1.2.7 || >=1.2.9 <2.0.0$ npm install compare-versions
Note: Starting from v5 the main export is now named like so: import { compareVersions } from 'compare-versions'.
Note: Starting from v4 this library includes a ESM version which will automatically be selected by your bundler (webpack, parcel etc). The CJS/UMD version is lib/umd/index.js and the new ESM version is lib/esm/index.js.
Will return 1 if first version is greater, 0 if versions are equal, and -1 if the second version is greater:
import { compareVersions } from 'compare-versions';
compareVersions('11.1.1', '10.0.0'); // 1
compareVersions('10.0.0', '10.0.0'); // 0
compareVersions('10.0.0', '11.1.1'); // -1
Can also be used for sorting:
const versions = [
'1.5.19',
'1.2.3',
'1.5.5'
]
const sorted = versions.sort(compareVersions);
/*
[
'1.2.3',
'1.5.5',
'1.5.19'
]
*/
The alternative compare function accepts an operator which will be more familiar to humans:
import { compare } from 'compare-versions';
compare('10.1.8', '10.0.4', '>'); // true
compare('10.0.1', '10.0.1', '='); // true
compare('10.1.1', '10.2.2', '<'); // true
compare('10.1.1', '10.2.2', '<='); // true
compare('10.1.1', '10.2.2', '>='); // false
The satisfies function accepts a range to compare, compatible with npm package versioning:
import { satisfies } from 'compare-versions';
satisfies('10.0.1', '~10.0.0'); // true
satisfies('10.1.0', '~10.0.0'); // false
satisfies('10.1.2', '^10.0.0'); // true
satisfies('11.0.0', '^10.0.0'); // false
satisfies('10.1.8', '>10.0.4'); // true
satisfies('10.0.1', '=10.0.1'); // true
satisfies('10.1.1', '<10.2.2'); // true
satisfies('10.1.1', '<=10.2.2'); // true
satisfies('10.1.1', '>=10.2.2'); // false
satisfies('1.4.6', '1.2.7 || >=1.2.9 <2.0.0'); // true
satisfies('1.2.8', '1.2.7 || >=1.2.9 <2.0.0'); // false
satisfies('1.5.1', '1.2.3 - 2.3.4'); // true
satisfies('2.3.5', '1.2.3 - 2.3.4'); // false
Applies the same rules used comparing version numbers and returns a boolean:
import { validate } from 'compare-versions';
validate('1.0.0-rc.1'); // true
validate('1.0-rc.1'); // false
validate('foo'); // false
Validate version numbers strictly according to semver.org; 3 integers, no wildcards, no leading zero or "v" etc:
import { validateStrict } from 'compare-versions';
validate('1.0.0'); // true
validate('1.0.0-rc.1'); // true
validate('1.0'); // false
validate('1.x'); // false
validate('v1.02'); // false
If included directly in the browser, the functions above are available on the global window under the compareVersions object:
<script src=https://unpkg.com/compare-versions/lib/umd/index.js></script>
<script>
const { compareVersions, compare, satisfies, validate } = window.compareVersions
console.log(compareVersions('11.0.0', '10.0.0'))
console.log(compare('11.0.0', '10.0.0', '>'))
console.log(satisfies('1.2.0', '^1.0.0'))
console.log(validate('11.0.0'))
console.log(validateStrict('11.0.0'))
</script>