10aday › tools
Type a version constraint such as ~1.2, ^0.3.1, ~> 2.1, ~=1.4.2 or >=1.2, <2.
You see how each package manager reads it and which versions it accepts.
The same string often means different things: ~1.2 stops before 1.3.0 in npm and Cargo, but allows every 1.x release in Composer.
| Tool | What this page shows for a pre-release such as 1.3.0-rc.1 |
|---|---|
| npm | A pre-release matches only if one comparator in the same range names the same major.minor.patch with a pre-release tag. For example, ^1.2.3-beta accepts 1.2.3-rc.1 but not 1.3.0-rc.1. Option includePrerelease is off. |
| Cargo | Same idea as npm (Rust crate semver): pre-releases are rejected unless a comparator names one on the same major.minor.patch. |
| Composer | The constraint itself includes pre-releases: ^1.2 covers 1.3.0-RC1. At install time, minimum-stability (default stable) filters them out unless you lower it or add a flag such as @RC. This page shows the constraint check only. |
| pip | This page shows PEP 440 range membership with pre-releases allowed. pip itself installs a pre-release only with --pre, when the specifier names a pre-release, or when no final release matches. Note that <2.0 never matches 2.0.0a1. |
| RubyGems | Pre-releases (1.3.0.rc1, or 1.3.0-rc.1 read as 1.3.0.pre.rc.1) sort before the release and are compared normally. gem install and Bundler only pick them when you ask for pre-releases. |
What actually gets installed, tested with each real tool: pre-release versions in five package managers.
Generated from the official implementations (node-semver 7.8.5, Rust semver 1.0.28, composer/semver 3.6.0, Python packaging 26.3, RubyGems 3.5.22). "invalid" means the tool rejects the constraint.
| Constraint | npm | Cargo | Composer | pip | RubyGems |
|---|---|---|---|---|---|
1.2.3 (bare) | exactly 1.2.3 | ^1.2.3 (≥1.2.3 <2.0.0) | exactly 1.2.3 | invalid (needs ==) | exactly 1.2.3 |
1.2 (bare) | 1.2.x (≥1.2.0 <1.3.0) | ^1.2 (≥1.2.0 <2.0.0) | exactly 1.2.0 | invalid | exactly 1.2 (= 1.2.0) |
~1.2.3 | ≥1.2.3 <1.3.0 | ≥1.2.3 <1.3.0 | ≥1.2.3 <1.3.0 | invalid | invalid |
~1.2 | ≥1.2.0 <1.3.0 | ≥1.2.0 <1.3.0 | ≥1.2.0 <2.0.0 | invalid | invalid |
^1.2.3 | ≥1.2.3 <2.0.0 | ≥1.2.3 <2.0.0 | ≥1.2.3 <2.0.0 | invalid | invalid |
^0.2.3 | ≥0.2.3 <0.3.0 | ≥0.2.3 <0.3.0 | ≥0.2.3 <0.3.0 | invalid | invalid |
^0.0.3 | ≥0.0.3 <0.0.4 | ≥0.0.3 <0.0.4 | ≥0.0.3 <0.0.4 | invalid | invalid |
~> 1.2 | read as ~1.2: ≥1.2.0 <1.3.0 | invalid | invalid | invalid | ≥1.2 <2.0 |
~> 1.2.3 | ≥1.2.3 <1.3.0 | invalid | invalid | invalid | ≥1.2.3 <1.3 |
~=1.4.2 | read as ~1.4.2: ≥1.4.2 <1.5.0 | invalid | invalid | ≥1.4.2, ==1.4.* | invalid |
~=1.4 | read as ~1.4: ≥1.4.0 <1.5.0 | invalid | invalid | ≥1.4, ==1.* (<2.0) | invalid |
1.* | ≥1.0.0 <2.0.0 | ≥1.0.0 <2.0.0 | ≥1.0.0 <2.0.0 | invalid (write ==1.*) | invalid |
1.x | ≥1.0.0 <2.0.0 | ≥1.0.0 <2.0.0 | ≥1.0.0 <2.0.0 | invalid | the literal version "1.x" |
* | any | any | any | invalid (empty = any) | invalid |
>=1.2, <2 (comma) | invalid | AND | AND | AND | AND (separate Gemfile arguments) |
>=1.2 <2 (space) | AND | invalid | AND | invalid | invalid |
^1.2 || ^2 | OR | invalid | OR | invalid | invalid |
1.2 - 2.3.4 | ≥1.2.0 ≤2.3.4 | invalid | ≥1.2.0 ≤2.3.4 | invalid | invalid |
==1.2.3 | invalid | invalid | exactly 1.2.3 | exactly 1.2.3 | invalid |
!=1.2.3 | invalid | invalid | not 1.2.3 | not 1.2.3 | not 1.2.3 |
~1.2.3 allows patch updates only (≥1.2.3 <1.3.0). ^1.2.3 allows minor and patch updates (≥1.2.3 <2.0.0).
Below 1.0.0 the caret is stricter: ^0.2.3 means ≥0.2.3 <0.3.0, and ^0.0.3 means exactly the 0.0.3 line. Cargo reads both operators the same way.
Composer's tilde lets the last number you wrote move: ~1.2 means ≥1.2 <2.0, while ~1.2.3 means ≥1.2.3 <1.3.0. Coming from npm, ~1.2 is the classic surprise.
~> (pessimistic operator) mean in a Gemfile?~> 2.1 means ≥2.1 and <3.0, and ~> 2.1.0 means ≥2.1.0 and <2.2. RubyGems drops the last number you wrote and bumps the one before it.
~= (compatible release) mean in pip?~=1.4.2 means ≥1.4.2 and ==1.4.*. ~=1.4 means ≥1.4 and ==1.* (any 1.x from 1.4). It works like Ruby's ~>. npm also accepts ~=, but reads it as its own tilde.
requires-python specifier allows (<=3.12 excludes 3.12.1)1.0.0-1 is older for npm, newer for pip)1.+, [1.0,2.0) and latest.release, and which version Gradle resolves.go.mod version for a commit with no tag, and what “invalid pseudo-version” errors mean.[1.0,2.0) and 1.*, and which version dotnet restore picks.[1.0,2.0) and (,1.5], and which version Maven picks.^ and ~ from [tool.poetry.dependencies] into [project] dependencies~1.2 trap~> vs ~= vs ~ — the “pessimistic” operator in RubyGems, pip, Composer, npm and Cargo|| — 1.x, 1.2 - 2.3, ^1 || ^3 and the partial-version trap in five package managers"1.2.3" is not a pin, compared with npm~1.2 is <2.0 and a bare "1.2" is exactly 1.2.0 in composer.json~= and PEP 440 specifiers — ~=1.4, ==1.4.*, != in requirements.txt, compared with Ruby ~>^ and ~ to PEP 440 — what ^0.2.3 or ~1.2 means in Poetry and how to write it in [project]