semver review
A prerelease can be newer than your minimum version and still fail your range check. The npm semver package parses semantic version strings, compares versions and checks npm-style ranges. It gives a plugin loader or release script a consistent way to decide which version labels it accepts. It cannot establish whether the corresponding code works with your application. This guide uses semver 7.8.5 and concentrates on keeping that acceptance policy explicit, especially for prereleases and versions below 1.0.
Use semver when you need npm-style version acceptance rules and can state your prerelease policy explicitly. Before wiring it into a loader or release job, turn the boundary cases below into checks against your own supported versions.
Answers from our run
semver or compare-versions: which should you use?
compare-versions: Consider compare-versions when the job is comparing version strings as greater, equal or lesser. Its registry description establishes that scope. This guide does not establish equivalence with semver's complete range grammar. Use semver when you need npm-style version acceptance rules and can state your prerelease policy explicitly.
When should you not use semver?
You need proof that an upgrade is compatible. A version label and a matching range cannot replace tests of the application that consumes it.
Use it if
- Your plugin loader accepts a declared range and needs to check a plugin's version before loading it.
- A release script must compare semantic versions numerically rather than sort their characters.
- You already have a list of available versions and need the highest one that satisfies your policy.
- You need npm-style caret, tilde or compound ranges and want their prerelease rules written into your checks.
- You need proof that an upgrade is compatible. A version label and a matching range cannot replace tests of the application that consumes it.
- Your identifiers are arbitrary dates, Git hashes or vendor strings that do not follow semantic versioning. Coercion can discard meaningful text rather than preserve your naming scheme.
- You expect this package to fetch registry releases, install dependencies or resolve an entire dependency graph. Its documented functions operate on versions, ranges and lists you provide.
- You only need to find version-shaped text in a log. A matching expression may be enough for that narrower task.
Setup reality
Install the version covered here with npm install semver@7.8.5, then use const semver = require('semver') in a CommonJS file. The npm manifest declares Node >=10. That is an upstream engine constraint, not a recommendation to deploy an old Node release or a runtime matrix reproduced here. The examples below are documentation-based illustrations for semver 7.8.5. They were not executed for this guide. No install timing, security audit or runtime compatibility measurement is claimed.
Validate the version and the range separately before you make an acceptance decision. semver.valid returns a parsed version string or null. A partial range such as 1.2 is valid range syntax even though it is not a complete version. An empty range also means any non-prerelease version, so reject blank input yourself when a missing policy should be an error. Treat null as a result your application must handle. Don't silently turn a missing match into the latest release.
Prereleases need a deliberate rule. By default, a prerelease only passes a comparator set when a comparator with the same major, minor and patch also carries a prerelease. Setting includePrerelease changes this behavior. It does not make an out-of-range version pass. Caret ranges below 1.0 have another boundary: ^0.2.3 accepts patch updates below 0.3.0, while ^0.0.3 stops before 0.0.4. Write checks around the boundaries your plugin or release policy cares about.
Coercion is a separate import decision. The documented translation of 4.6.3.9.2-alpha2 is 4.6.3, which loses both the extra components and suffix. Keep the original input if you need to explain that transformation. Build metadata needs a policy too: compare ignores it for precedence, while compareBuild uses it to order otherwise equal versions. Neither rule tells you which artifact was tested.
The ratings are editorial judgments from documentation, package metadata and release notes, not benchmark results. On a 1-5 scale, 1 means little usable support in those sources, 3 means documented support with material evaluation gaps, and 5 requires direct validation of the relevant behavior. API stability assesses the documented contract and changes, docs quality assesses explanations of edge cases, maintenance assesses release evidence, and ecosystem assesses integration evidence. No dimension gets 5 from documentation alone.
Patterns
Reject an incomplete version validate-version
const semver = require('semver')
const input = '1.2'
const version = semver.valid(input)
if (version === null) {
throw new Error('A complete semantic version is required')
}Documentation-based, unexecuted illustration. valid('1.2') returns null. Version syntax and range syntax accept different inputs. valid is a parser check, not a character-for-character canonical-format check.
Reject a blank policy before parsing validate-range
const semver = require('semver')
const input = '^1.2.3'
if (input.trim() === '') throw new Error('A range is required')
const range = semver.validRange(input)
if (range === null) throw new Error('Invalid range')
const accepted = semver.satisfies('1.4.0', range) // trueDocumentation-based, unexecuted illustration. An empty range is valid and means any non-prerelease version by default. The explicit blank check is application policy.
Make the zero-major boundary visible caret-below-one
const semver = require('semver')
const patchAccepted = semver.satisfies('0.2.9', '^0.2.3') // true
const minorRejected = semver.satisfies('0.3.0', '^0.2.3') // false
const nextPatchRejected = semver.satisfies('0.0.4', '^0.0.3') // falseDocumentation-based, unexecuted illustration. A caret preserves the leftmost non-zero component. These results express permitted labels, not tested compatibility between the releases.
Keep preview acceptance on one version tuple prerelease-default
const semver = require('semver')
const sameTuple = semver.satisfies(
'1.2.3-beta.4', '>=1.2.3-beta.2 <2.0.0'
) // true
const nextTuple = semver.satisfies(
'1.2.4-beta.1', '>=1.2.3-beta.2 <2.0.0'
) // falseDocumentation-based, unexecuted illustration. Default prerelease matching requires a prerelease comparator with the same major, minor and patch. A later preview does not inherit that opt-in.
Accept previews within explicit bounds prerelease-opt-in
const semver = require('semver')
const version = '1.3.0-beta.1'
const range = '>=1.2.3 <2.0.0'
const stablePolicy = semver.satisfies(version, range) // false
const previewPolicy = semver.satisfies(version, range, {
includePrerelease: true
}) // trueDocumentation-based, unexecuted illustration. includePrerelease removes the extra prerelease exclusion. The ordinary comparator bounds still apply.
Select from a supplied release list select-available-version
const semver = require('semver')
const available = ['1.2.3', '1.9.0', '2.0.0']
const selected = semver.maxSatisfying(available, '^1.2.3')
if (selected === null) throw new Error('No acceptable release')
console.log(selected) // '1.9.0'Documentation-based, unexecuted illustration. maxSatisfying only chooses from your list and returns null if nothing matches. It does not query npm or download the selected package.
Sort numeric components in order sort-by-precedence
const semver = require('semver')
const versions = ['1.10.0', '1.2.0', '1.3.0-beta.1']
const ordered = [...versions].sort(semver.compare)
console.log(ordered)
// ['1.2.0', '1.3.0-beta.1', '1.10.0']Documentation-based, unexecuted illustration. compare sorts by semantic-version precedence. A preview can appear in this ordering even when your default range policy would exclude it.
Distinguish precedence from artifact labels separate-build-metadata
const semver = require('semver')
const a = '1.2.3+build.1'
const b = '1.2.3+build.2'
const samePrecedence = semver.compare(a, b) === 0 // true
const buildOrder = semver.compareBuild(a, b) // -1Documentation-based, unexecuted illustration. compare ignores build metadata for precedence. compareBuild considers it when versions are otherwise equal. Build ordering does not establish artifact equivalence.
Keep the original before coercion coerce-imported-text
const semver = require('semver')
const original = '4.6.3.9.2-alpha2'
const parsed = semver.coerce(original)
if (parsed === null) throw new Error('No version found')
const normalized = parsed.version // '4.6.3'
console.log({ original, normalized })Documentation-based, unexecuted illustration. coerce intentionally ignores surrounding text and truncates extra components. Use valid when your input contract requires an already formed version.
Generate the next preview label increment-preview
const semver = require('semver')
const next = semver.inc('1.2.3', 'prerelease', 'beta')
if (next === null) throw new Error('Could not increment version')
console.log(next) // '1.2.4-beta.0'Documentation-based, unexecuted illustration. The documented identifier overload supplies the beta prefix. This computes a version string. Your script must still write metadata, test the release and publish it separately.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| compare-versions | npm | Consider compare-versions when the job is comparing version strings as greater, equal or lesser. Its registry description establishes that scope. This guide does not establish equivalence with semver's complete range grammar. |
| semver-regex | npm | Consider semver-regex when the job is matching semantic-version text. Its registry description promises a regular expression for that task. Choose a range evaluator instead when the decision is whether a version satisfies a policy. |
More infra guides
boto3 · opentelemetry-api · @opentelemetry/api · psutil · distro · @aws-sdk/client-s3 · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.