10aday › tools

Version sorter: sort version numbers the npm, Cargo, Composer, pip and RubyGems way

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.

Compare two versions

Where package managers disagree

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.

ABnpmCargoComposerpipRubyGemsWhy

The comparison columns are computed by the same engine as the sorter when the page loads.

The rules in one paragraph each

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.

FAQ

How do I sort version numbers correctly?

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.

Is 1.0.0-rc.1 older or newer than 1.0.0?

Older, in all five package managers: a pre-release always comes before the final release with the same numbers.

Why is 1.0.0-alpha.10 newer than 1.0.0-alpha.2?

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.

Is 1.0.0-1 older or newer than 1.0.0?

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.

Are 1.0 and 1.0.0 the same version?

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.

Does build metadata like 1.0.0+build.1 change the order?

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.

Where does dev-master go when Composer sorts versions?

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.

Sources