What ^1.2.3 matches in npm

>=1.2.3 <2.0.0

^1.2.3 matches >=1.2.3 <2.0.0: version 1.2.3 and every later 1.x release, up to but not including 2.0.0. The caret keeps the major version fixed, on the SemVer 2.0.0 promise that only a major bump breaks the public API.

Against real versions

1.2.2         no    below the floor
1.2.3         yes
1.2.10        yes   10 > 3: each part compares as a number
1.3.0         yes
1.9.9         yes   the highest match
1.4.0-beta.1  no    a prerelease the range doesn't name
2.0.0         no
2.0.0-rc.1    no

On a fresh install npm takes the version the latest tag points to if it fits the range, and otherwise the highest match: 1.9.9 here.

Gotchas

  • Prereleases stay out. 1.4.0-beta.1 is inside the bounds, but node-semver, npm’s range engine, admits a prerelease only when the range names one on the same 1.4.0. ^1.2.3 never pulls in a beta by itself.
  • The lockfile decides first. package-lock.json holds the exact version installed. npm install keeps it while it still satisfies ^1.2.3, so 1.9.9 arrives only through npm update or a fresh lockfile. npm ci installs the lockfile exactly and stops with an error if it doesn’t match package.json.
  • The caret is also a floor. ^1.2.3 rejects 1.2.2. Write the lowest version you have tested with, not an older one you hope works.
  • The -0 in tooling output. node-semver compiles the range to >=1.2.3 <2.0.0-0. The -0 is the lowest possible prerelease of 2.0.0, so 2.0.0’s prereleases stay out even when includePrerelease lets other prereleases in.

Where the caret comes from

npm install pkg writes ^ plus the installed version because save-prefix defaults to ^; pnpm’s savePrefix and Yarn’s defaultSemverRangePrefix default to ^ as well. In a pnpm workspace, workspace:^ on a sibling package at 1.5.0 is written out as ^1.5.0 when you publish.

Elsewhere

  • Cargo: ^1.2.3 and the plain "1.2.3" both mean >=1.2.3, <2.0.0; the caret is Cargo’s default.
  • Composer: ^1.2.3 is >=1.2.3 <2.0.0, as in npm.
  • In code and the shell:
semver.satisfies('1.9.9', '^1.2.3')   // true
semver.satisfies('2.0.0', '^1.2.3')   // false
npx semver -r '^1.2.3' 1.2.2 1.9.9 2.0.0   # prints 1.9.9

Try it in the Semver Range Checker

^1.2.3 means >=1.2.3 <2.0.0 — from 1.2.3 up to, but not including, 2.0.0

4 of 8 versions match — the newest is 1.9.9.

Each version · 8 versions
VersionFits the range
1.2.2
1.2.3
1.2.10
1.3.0
1.9.9
1.4.0-beta.1
2.0.0
2.0.0-rc.1

Follows node-semver, npm's range grammar: caret ^, tilde ~, x-ranges 1.2.x, hyphen ranges 1.2.3 - 2, || and comparators. A prerelease like 1.9.9-beta only matches when the range names a prerelease on the same 1.9.9 — that is why ^1.2.3 skips it. Everything runs in this page, nothing is uploaded.

Runs in your browser. Nothing you enter is sent anywhere.