Front-End Web Development introduces MAJOR.MINOR.PATCH. What matters in a Node project is the range you write down, because it decides which future releases install without you asking. npm 2,036 evaluates ranges with the semver package (github.com/npm/node-semver (https://github.com/npm/node-semver 5,467 ), ISC, currently 7.8.5), and you can run that resolver by hand:
npx semver -r "^1.2.3" 1.2.3 1.9.0 2.0.0 1.2.21.2.3 1.9.0
The caret is the default npm writes, and it means "anything that does not change the leftmost non-zero digit". That last clause is the trap: for ^0.2.0 the leftmost non-zero digit is the minor, so 0.3.0 is excluded. Pre-1.0 packages behave as if every minor bump were a major one.
| Range | Matches | Excludes |
|---|---|---|
| ^1.2.3 | 1.2.3 to <2.0.0 | 2.0.0, 1.2.2 |
| ^0.2.0 | 0.2.0 to <0.3.0 | 0.3.0 |
| ~1.2.3 | 1.2.3 to <1.3.0 | 1.3.0 |
| >=1.2 <2 || 3.x | 1.9, 3.4 | 2.1 |
| 1.2.3 | exactly 1.2.3 | everything else |
Prereleases are deliberately antisocial: ^1.2.3 matches neither 2.0.0-rc.1 nor 1.3.0-beta.1, because a range admits a prerelease only when it names that exact major.minor.patch tuple. Write ^1.2.3-0 to opt in.
When a transitive dependency pins something you need to move, an overrides object such as { "semver": "7.8.5", "some-plugin": { "glob": "$glob" } } rewrites the tree without forking. The $glob form means "whatever version the root already depends on", which keeps the override honest as you upgrade. pnpm 69,400 calls this pnpm.overrides; Yarn 11,798 calls it resolutions.