10aday › tools
Sorting versions as text puts 1.10 before 1.9. Sorting them “by numbers” is not enough either: each package manager has its own rules
for pre-releases, post-releases, build metadata and missing parts. Paste a list of versions to see the order used by
npm (node-semver), Cargo (crate semver), Composer, pip (PEP 440) and RubyGems, side by side, and where they disagree.
“=” marks a version that this package manager considers equal to the one above it. Greyed versions are not valid there. Runs in your browser; nothing is sent anywhere.
Each row compares A with B. “<” means A is older, “>” means A is newer, “—” means at least one of them is not a valid version there.
| A | B | npm | Cargo | Composer | pip | RubyGems | Why |
|---|
The comparison columns are computed by the same engine as the sorter when the page loads.
npm and Cargo (SemVer 2.0). Exactly three numbers, no leading zeros. A hyphen starts a pre-release, which comes before the release.
Pre-release parts are split on dots: digit-only parts are compared as numbers, others as text (ASCII, so RC < alpha). A +build suffix is ignored.
npm accepts a leading v; Cargo does not.
pip (PEP 440). Any number of release numbers, padded with zeros. Order: .devN < aN < bN < rcN < release < .postN.
Many spellings are normalized (1.0.0-rc.1 = 1.0.0rc1, 1.0.0-1 = 1.0.0.post1). A +local label sorts after the same public version.
Composer. Versions are normalized to four numbers (1.2 → 1.2.0.0) plus a stability: dev < alpha < beta < RC < stable < patch.
Then PHP's version_compare orders them. Branch names (dev-main) are not versions; dev-master is read as 9999999-dev.
RubyGems. Any dot-separated parts. A part containing a letter makes the whole version a pre-release (1.0.0.post1 is older than 1.0.0!).
A hyphen is read as .pre.. Trailing zeros do not count (1.0 = 1).
Related: to check which versions a constraint such as ^1.2 or ~> 2.1 accepts, use the Version Constraint Checker. For Java, see how Maven orders versions in the Maven version range checker. For Go, see what a pseudo-version such as v1.6.1-0.20241114170450-2d3c2a9cc518 means in the Go pseudo-version decoder.
For Python, see the requires-python checker and the pip ~= guide; for npm ranges, the tilde vs caret guide.
Do not sort them as text: as text, 1.10 comes before 1.9. Compare the numbers one by one, then apply your package manager's rule for pre-releases (1.0.0-rc.1 comes before 1.0.0). Each package manager has slightly different rules, which is why this tool shows all five orders.
Older, in all five package managers: a pre-release always comes before the final release with the same numbers.
Identifiers made only of digits are compared as numbers, so 10 > 2, in all five package managers. Text sorting gets this wrong. Prefer alpha.2 to alpha2: for npm and Cargo, 1.0.0-alpha10 is older than 1.0.0-alpha2, because alpha10 and alpha2 are compared as text.
It depends. For npm, Cargo and RubyGems it is a pre-release, so it is older. For pip (PEP 440), 1.0.0-1 means the post-release 1.0.0.post1, so it is newer. Composer rejects it.
For pip, Composer and RubyGems, yes: missing parts count as zeros. For npm and Cargo, 1.0 is not a valid version: a full version needs three numbers.
Not for npm, Cargo or Composer: build metadata is ignored when ordering. In pip, +build.1 is a local version label, and 1.0.0+build.1 sorts after 1.0.0. RubyGems rejects the plus sign.
Composer's Semver::sort reads dev-master, dev-default and dev-trunk as 9999999-dev, so they come after every numbered version. Other branch names, such as dev-main or dev-feature, have no order between them.
cmp_precedence)Semver::sort)