What this tool does
npm reads a dependency range in package.json by turning it into plain comparators. ^1.2.3 becomes >=1.2.3 <2.0.0-0, ~1.2.3 becomes >=1.2.3 <1.3.0-0, 1.x becomes >=1.0.0 <2.0.0-0, and 1.2.3 - 2.3.4 becomes >=1.2.3 <=2.3.4. The checker shows that form for every part of the range you type, explains each part, and draws the range on a version line. Each version you paste is tested the way npm tests it. Every comparator must pass in at least one || alternative. A prerelease such as 2.0.0-beta.1 matches only when a comparator in that alternative names a prerelease of the same major.minor.patch, unless you turn on Include prereleases. Each result says why: below the range, above it, the wrong exact version, or a prerelease the range skips. The highest match is what npm install picks when there is no lockfile, so the tool shows that too. Loose parsing reads ranges the way npm does, accepting =1.2.3 and ignoring tokens it can’t read. Compare explains which of two versions is higher and the release type between them. Bump lists every result of npm version, with --preid. Sort orders a list by precedence, as semver.sort does.
Example input and output
Range: ^10.2.6
Versions: 10.2.4, 10.2.6, 11.0.1^10.2.6 means >=10.2.6 <11.0.0-0: any 10.x version from 10.2.6 up, but not 11.0.0.
10.2.4 no Below the range, which starts at 10.2.6
10.2.6 yes In the range
11.0.1 no Above the range, which stops before 11.0.0: ^ never moves to a new major version
npm install picks: 10.2.6A package that declares minimatch ^10.2.6 can never get 11.0.1, whatever you run. The package has to widen its range, or you can force the version with overrides in your own package.json. Load this with the minimatch fix example.
Range: ^0.2.3
Versions: 0.2.3, 0.2.9, 0.3.0, 1.0.0^0.2.3 means >=0.2.3 <0.3.0-0: any 0.2.x version from 0.2.3 up, but not 0.3.0.
0.2.3 yes In the range
0.2.9 yes In the range
0.3.0 no Above the range, which stops before 0.3.0: on 0.x, ^ allows patch updates only
1.0.0 no Above the range, which stops before 0.3.0: on 0.x, ^ allows patch updates only
npm install picks: 0.2.9SemVer says anything may change while the major version is 0, so npm treats the first non-zero part as the breaking one. ^0.0.3 goes further and allows only 0.0.3.
Range: ^2.0.0-beta.1
Versions: 2.0.0-beta.1, 2.0.0-beta.2, 2.0.0, 2.1.0-beta.1^2.0.0-beta.1 means >=2.0.0-beta.1 <3.0.0-0: any 2.x version from 2.0.0-beta.1 up, but not 3.0.0.
2.0.0-beta.1 yes In the range: the range names a 2.0.0 prerelease
2.0.0-beta.2 yes In the range: the range names a 2.0.0 prerelease
2.0.0 yes In the range
2.1.0-beta.1 no Prerelease of a different version: only 2.0.0 prereleases can match
npm install picks: 2.0.0Opting in to one beta doesn’t opt you in to every later beta. 2.1.0-beta.1 is inside the bounds, but npm skips it because no comparator names a 2.1.0 prerelease.
Common errors and fixes
- npm error notarget No matching version found for minimatch@^12.0.0.
- No published version satisfies the range (code ETARGET). Paste the output of npm view minimatch versions --json under Versions to test to see which versions exist and where the range falls. Usually the range names a major that isn’t out yet, or only prereleases of it exist. It can also be a typo, or a registry that doesn’t have the package.
- npm audit or a scanner wants a fix in a new major, and npm update doesn’t install it
- npm update only moves within the ranges in package.json, including the ranges of the packages that depend on it, and ^ never crosses a major version. Check the declared range here against the fixed version. If it is outside, upgrade the package that declares the range, ask its maintainers to widen it, or pin the fix with overrides in your root package.json after testing that it works.
- ^0.2.3 doesn’t accept 0.3.0
- That is by design. On 0.x, ^ allows patch updates only, because a 0.x minor release may break the API. Write ^0.3.0 or >=0.2.3 <0.4.0 if you have tested the newer version.
- 2.0.0-beta.1 doesn’t match >=1.0.0
- A prerelease matches only when a comparator in the same alternative names a prerelease of that major.minor.patch, so nobody gets a beta by accident. Use >=2.0.0-beta.1 to opt in, or test with Include prereleases on, which is node-semver’s includePrerelease option. npm install doesn’t use that option.
- Invalid tag name ">=1.2.3 && <2.0.0" of package "x@>=1.2.3 && <2.0.0": Tags may not have any characters that encodeURIComponent encodes.
- npm treats a spec that isn’t a valid version or range as a dist-tag, and this one isn’t a valid range. Join comparators with a space (>=1.2.3 <2.0.0) and alternatives with ||. The checker points to the part it can’t read.
- `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync.
- A range in package.json no longer accepts the version recorded in the lockfile, often after someone edited the range by hand. Check the range against the locked version here, then run npm install to update the lockfile and commit both files.
Common use cases
- Checking whether a version a security advisory asks for is inside the range a dependency declares
- Seeing which version npm install would resolve from the versions on the registry
- Choosing between ^, ~ and an exact version when adding a dependency
- Explaining 0.x caret ranges, hyphen ranges and || unions in a code review
- Finding out why a beta or release candidate isn’t matched by a range
- Working out the next version, and the npm version command, before a release
Privacy and security notes
- Ranges and versions are parsed in this browser tab. Nothing you type is sent to DevPrix or to the npm registry. The tool never looks anything up, so paste the versions you want to test.
- Share puts the range and the version list in the link’s #fragment, which browsers don’t send to servers. Anyone you send the link to sees the same check.
Frequently asked questions
What is the difference between ^ and ~ in package.json?
^ allows any change that keeps the first non-zero number: ^1.2.3 accepts minor and patch updates up to, but not including, 2.0.0. ~ allows patch updates when you give a minor: ~1.2.3 stops before 1.3.0. With only a major, ~1 is the same as 1.x. npm install <pkg> saves a ^ range by default, because save-prefix defaults to ^.
Why doesn’t npm install the newest version that matches my range?
Because package-lock.json records exact versions. npm install uses them as long as they still satisfy the ranges in package.json. If a range no longer accepts the locked version, package.json wins and npm updates the lockfile. npm update moves packages to the newest version their ranges allow and leaves package.json alone unless you add --save.
What does the -0 in <2.0.0-0 mean?
-0 is the lowest prerelease there is, so <2.0.0-0 keeps out 2.0.0 and every 2.0.0 prerelease, such as 2.0.0-beta.1. node-semver writes ^ and ~ upper bounds this way so that a beta of the next major stays out, even when prereleases are allowed.
Is build metadata like +build.5 part of the comparison?
No. SemVer says build metadata must be ignored when working out precedence, so 1.2.3+build.5 satisfies the range 1.2.3, and npm strips +… from ranges before reading them. Sort mode still orders versions that differ only in build metadata by their build, as semver.sort does.
Does this match what npm itself does?
Yes, for valid ranges. The range rules follow node-semver, the library npm uses. The tool was checked against node-semver 7.8.5 and against the 7.7.4 copy bundled with npm 11, with no differences. npm install also checks the latest dist-tag first and passes over deprecated versions and ones whose engines don’t fit your Node.js, which a list of versions can’t show.
Do Cargo and Composer read ^ and ~ the same way?
Mostly, with one big exception. Cargo treats a bare version such as 1.2.3 as ^1.2.3, and its ^ and ~ match npm’s, including the 0.x rules. Composer’s ^ matches npm’s, but its ~1.2 means >=1.2 <2.0.0, where npm’s ~1.2 stops before 1.3.0. Both also accept commas between comparators, which npm doesn’t.
Guides
- ^ vs ~ in package.json: how npm version ranges workWhat ^ and ~ allow in package.json, the 0.x special cases, prereleases and lockfiles, and why npm can't pick up a security fix released in a new major version.