Understand ~ and ^ in package.json
Compare npm tilde and caret ranges, including 0.x and prerelease rules, and use a lockfile to record the dependency tree you tested.
~1.2.3 allows patch releases starting at 1.2.3. ^1.2.3 also allows later minor releases within major version 1. Both express acceptable versions; neither guarantees that an upstream release will work with your application.
Compare the ranges
For ordinary stable versions:
| Declaration | Accepted stable versions |
|---|---|
~1.2.3 |
>=1.2.3 <1.3.0 |
^1.2.3 |
>=1.2.3 <2.0.0 |
1.2.3 |
Exactly 1.2.3 |
* or x |
Any stable version |
~1.2 |
>=1.2.0 <1.3.0 |
^1 |
>=1.0.0 <2.0.0 |
The shorthand “tilde fixes the minor version; caret fixes the major version” works for the first two rows, but breaks down for zero-major versions and incomplete version numbers. For example, ~1 allows stable releases throughout major version 1.
Ranges normally exclude prereleases such as 1.3.0-beta.1. Explicit prerelease comparators have additional matching rules; do not assume a broad-looking range automatically includes every beta release.
Account for version zero
Caret ranges preserve the leftmost nonzero component of a complete version:
^0.2.3accepts stable versions from0.2.3up to, but excluding,0.3.0.^0.0.3accepts only stable version0.0.3.~0.2.3accepts the same stable interval as^0.2.3.
Missing components change the calculation: ^0.0 accepts stable versions below 0.1.0, rather than pinning one patch. Review the actual range instead of applying the complete-version rule mechanically.
Pair the range with a lockfile
In an application, commit package-lock.json and test dependency updates. A compatible lockfile records exact resolutions, while the manifest declares the range used when resolution is needed, including deliberate updates. Adding one dependency does not imply that npm upgrades every other dependency.
Use npm ci for a clean installation based on the lockfile. It fails if the manifest and lockfile disagree, removes an existing node_modules, and does not rewrite the lockfile to resolve that disagreement. Use the same relevant installation flags that produced the lockfile. A lockfile improves dependency reproducibility; operating systems, native modules, lifecycle scripts, and external services can still affect a build.
For a library, choose dependency and peer-dependency ranges that you actually support. Wider ranges can improve compatibility, but do not eliminate peer conflicts. Pinning a problematic dependency can make updates deliberate; it also makes reviewing and applying fixes your responsibility.
FAQ
Does a lockfile make the range irrelevant? No. It records the current resolution; the range constrains future resolution and updates.
What if a package breaks semantic versioning? Test upgrades, inspect release notes, and narrow or pin the dependency when justified. A patch-only range is not a guarantee against regressions.
What does npm save by default? The usual save-prefix default is ^, but configuration and --save-exact can change that. Check npm config get save-prefix; npm config set save-prefix '~' changes your preference.
Related reading
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan