Menu

Guidefor developers5 min read

How to sort Minecraft versions in code after calendar versioning

Semver parsers put 1.21.11 above 26.2 and break. Why Minecraft version strings cannot be compared numerically, and what to sort on instead in code.

Why comparing the name fails

A Minecraft version name is an identifier, not a number. Three separate assumptions break on it.

Lexical sorting fails inside a single line. Compared character by character, 1.21.11 sorts below 1.21.2, because the fourth character is 1 in one and 2 in the other. Every release after .9 in a line is affected.

Semver fails on ordering within a version. Given 26.2-snapshot-8 and 26.2-pre-6, semver compares the prerelease identifiers alphanumerically, gets pre before snapshot, and reports the pre-release as older. The real order is the opposite: snapshots come first, then pre-releases, then release candidates, then the release. Semver also cannot parse 26.2 at all, since it has two components rather than three, and it has nothing to say about 25w46a.

Cross era comparison fails on assumptions that were never written down. Plenty of code assumed the first component is always 1 and treated the rest as the real version. That code now reads 26.2 as either invalid or as major version 26, and neither answer tells it that 26.1 is the direct successor of 1.21.11 with nothing in between.

The shapes a version name can take

All of these are live in the dataset today.

ShapeExampleNotes
Pre-classic and alphard-132211, rd-20090515No numeric component at all
Legacy release1.21, 1.21.11Two or three components
Legacy weekly snapshot25w46aYear, week, letter
Legacy pre-release1.21.11-pre1No separator before the number
Legacy release candidate1.21.11-rc3Same
Older pre-release1.14 Pre-Release 1Contains spaces
Calendar release26.1, 26.2, 26.1.2Year and drop, optional patch
Calendar snapshot26.3-snapshot-5Dash separated throughout
Calendar pre-release26.2-pre-6Dash before the number
Calendar release candidate26.2-rc-2Dash before the number
April Fools24w14potato, 3D Shareware v1.34Arbitrary strings

Note that the separator convention changed with the era. Legacy used 1.21.11-pre1, calendar uses 26.2-pre-6. A regex written for one does not match the other.

Sort on release order, not on the name

The version manifest is already in chronological order. Read the array position once at import time, store it as an integer, and make that integer the only thing you ever sort on.

curl -s https://launchermeta.mojang.com/mc/game/version_manifest_v2.json \
  | jq -r '.versions | reverse | to_entries[] | "\(.key)\t\(.value.id)"' | tail -20

On this site that column is sortIndex, unique across all 903 versions, running from 0 for rd-132211 up to 902 for the newest snapshot. Sorting becomes an integer comparison with no parsing:

SELECT name, era, "releaseDate"
FROM "GameVersion"
WHERE type = 'RELEASE'
ORDER BY "sortIndex" DESC
LIMIT 10;

In application code, keep a map from name to index and compare through it. Anything not in the map is a version you have not imported, which is a data problem to surface rather than a string to guess at.

const order = new Map(versions.map((v) => [v.name, v.sortIndex]));

function compare(a: string, b: string): number {
  const ia = order.get(a);
  const ib = order.get(b);
  if (ia === undefined || ib === undefined) throw new Error(`unknown version: ${ia === undefined ? a : b}`);
  return ia - ib;
}

Store an era flag beside it so the interface can group calendar and legacy versions without re-deriving the split from the name. Release date works as a secondary display field, but not as the sort key: several versions share a date, and re-releases muddy it.

Data version as a numeric fallback

The data version is a monotonically increasing integer that Mojang bumps for world format changes. It is tempting as a sort key because it is already a number, and it is the right tool when you are reading a world save rather than a name. As a general ordering it has four defects, all present in the current data:

  • It does not always exist. 126 of 903 versions carry no data version, including everything before 1.4.5.
  • Early values are negative. 1.4.5 reports -45 and 1.4.6 reports -43.
  • Values repeat. 15w33a and 15w33b both report 111, 16w43a and 16w44a both report 817, 18w43a and 18w43b both report 1902.
  • It moves backwards across parallel branches. 20w51a reports 2687 and the later 1.16.5-rc1 reports 2585, because the 1.16.5 branch forked earlier. The same happens at the era boundary, where 26w14a reports 5000 and the later 26.2-snapshot-1 reports 4883.

Use it to break ties within one branch, or to identify a world, and read the data version guide before relying on it further.

Snapshots, pre-releases and release candidates

Do not infer the type from the name either. Store it. The manifest distinguishes the types, and the calendar era added its own spellings.

Protocol numbers are a related trap. Modern snapshots, pre-releases and release candidates set bit 30 of the protocol version, so 26.3-snapshot-5 reports 1073742151 while release 26.2 reports 776. No release has the high bit set, and the maximum release protocol today is 776. Sorting a mixed list on protocol therefore puts every recent snapshot above every release. The convention also did not exist for older snapshots, so it is not a reliable type test on its own. The protocol version guide covers what the number is actually for.

April Fools builds and other outliers

Nine April Fools versions exist, from 15w14a in 2015 to 26w14a in 2026. They sit in the manifest in chronological position, which is correct, but they are not on the main development line: 24w14potato reports data version 3824 while the earlier 24w13a reports 3826. Flag them at import and exclude them from any "latest snapshot" query. 1.RV-Pre1, 3D Shareware v1.34 and 23w13a_or_b also carry no data version at all, so any code path that assumes one will fail on them.

Test cases worth keeping

Pin these as assertions. Each one catches a different class of bug.

AssertionCatches
1.21.11 is newer than 1.21.2Lexical sorting
26.2 is newer than 1.21.11Era assumptions and ^1\. regexes
26.2-snapshot-8 is older than 26.2-pre-6Semver prerelease ordering
26.2-pre-6 is older than 26.2-rc-2Stage ordering in the calendar era
26.2-rc-2 is older than 26.2Release ranks above its candidates
25w46a is older than 1.21.11Snapshot names against release names
1.21.11 is the immediate predecessor of 26.1The era boundary has no gap
24w14potato is excluded from latest snapshotApril Fools handling

What could change

Mojang has changed the scheme twice in one year, so treat any parsing rule as temporary. A third calendar component beyond 26.1.2, a new snapshot spelling, or another naming experiment would all land in the manifest before they land anywhere else. The defence is the same in each case: sort on the imported order, never on the string.

To check, re-fetch the manifest with the command above and compare the tail against the version list on this site. If the newest entry there does not match latest.snapshot in the manifest, our sync is behind, which is visible on the status page.

Frequently asked

Why does semver put 1.21.11 above 26.2?

Usually because the code was never really doing semver. Most launchers and mod tools matched release names with a regex anchored on 1. and dropped anything else into an unknown bucket that sorts last, so 26.2 landed below every 1.x release. A strict semver parser rejects 26.2 outright, because it has two components rather than three.

Is the data version safe to sort on?

Only within one development branch, and only where it exists. 126 of the 903 versions on this site carry no data version at all, several pairs share one value, and it moves backwards whenever two branches are open at once. Use it as a tiebreak or a sanity check, never as the primary key of your ordering.

How do I detect whether a version is legacy or calendar?

Do not parse the name. Store an era flag when you import the manifest. If you must derive it, the rule is that a leading component of 1 is legacy and a leading two digit year of 25 or higher is calendar, but that rule needs revisiting every time Mojang changes the scheme.

Where do I get an ordered list of every version?

Mojang's version manifest at launchermeta.mojang.com lists every version in chronological order. Read the array position, store it, and sort on that. The ordered list is also published on this site.

Referenced on this site

Last reviewed 2026-07-27. Version data on this site updates automatically; this guide is reviewed by hand when the ecosystem changes.