Versions and dependencies
Read version ranges
Predict which releases satisfy caret, tilde, exact, comparison, tag, and prerelease specifications.
A dependency range in package.json is an update policy written as a string. It tells npm which releases may be installed. Copying ^ prefixes without understanding them is how you get surprise breakages in CI.
The ranges you will see most
{
"dependencies": {
"unicode-properties": "1.0.1",
"fast-check": "~3.23.0",
"tsup": "^8.0.0"
}
}
1.0.1(exact): only that version. Safe for fragile pins, but you will miss patches.~3.23.0(tilde): allows patch updates within3.23.x, not3.24.0.^8.0.0(caret): allows compatible updates per semver rules. For8.0.0, npm admits>=8.0.0 <9.0.0.
Test a range before you commit it
npm ships a semver checker:
npx semver -r '^8.0.0' 8.0.1 8.4.0 9.0.0
Output:
8.0.1
8.4.0
Version 9.0.0 is omitted because it falls outside the caret range for a 8.x dependency.
For zero-major packages the rules shift. Test them explicitly:
npx semver -r '^0.2.0' 0.2.1 0.3.0 1.0.0
Here 0.3.0 is excluded. Caret ranges on 0.x are tighter than on 1.x.
Prereleases and tags
A version like 2.0.0-beta.1 will not satisfy ^2.0.0 unless you opt into prereleases. Tags such as latest and next point at different dist-tags on the registry. Most apps should follow latest unless they chose otherwise.
Pick ranges on purpose
For @acme/slugify-title, I pin runtime dependencies narrowly when a patch release already burned me once. For build tools in devDependencies, a caret on the major version is usually fine because consumers never install them.
When you change a range, note why in the PR. “Copied from another repo” is not a policy.
The npm outdated command shows what newer versions exist without writing the lockfile yet. I scan that output weekly, then update one package at a time with evidence instead of clicking “update all”.
Lesson completed