How Version Numbers Actually Work
Semantic versioning, calendar versioning, build identifiers and security patch levels — four incompatible schemes, what each one promises, and where those promises break down.
Four schemes pretending to be one
A version number looks like a universal convention and behaves like a local dialect. The string 4.2.1 means something specific and useful if the project follows semantic versioning. The string 2026.08 means something entirely different. The string 22631.4317 means something else again, and the string 2026-08-05 attached to an Android build is not a version at all — it is a statement about which security fixes are present.
Because these schemes look superficially similar, they get read as if they were interchangeable, and almost every practical mistake in release tracking starts there. Someone sees a jump from 1.9 to 2.0 and assumes a rewrite; someone else sees 118 to 119 and assumes a trivial increment. Both readings can be right or wrong depending entirely on which scheme is in play.
This guide covers the four schemes you will actually meet, what each one is trying to tell you, and — more usefully — where each one is routinely wrong.
Semantic versioning: a promise, not a fact
Semantic versioning splits a version into three numbers: major, minor and patch. The contract is straightforward. A patch bump means bug fixes only, with no change to the interface. A minor bump means functionality was added in a way that existing code keeps working. A major bump means something that used to work no longer does.
That contract is the reason automated dependency tooling exists at all. If patch and minor releases are genuinely safe, a machine can apply them without a human reading the notes, and only major bumps need attention. Enormous amounts of infrastructure rest on that assumption.
The assumption is a convention, not a guarantee, and it fails in predictable ways. A minor release tightens a type definition and breaks a build that compiled yesterday. A patch release fixes a bug that downstream code had come to rely on. A project raises its minimum runtime version in a minor, stranding anyone below it. None of these are bad-faith — they are judgement calls where the maintainer decided the change was not breaking and a subset of users disagreed.
- Treat a patch bump as probably safe, not certainly safe.
- Read the notes on minor releases of anything that sits close to your build — compilers, type systems, bundlers, linters.
- Assume a major bump has a migration guide, and that the guide is incomplete.
- Pre-1.0 versions carry no promises at all. Under semantic versioning's own rules, anything below 1.0.0 can break in any release.
Calendar versioning: honest about what it is not
Calendar versioning encodes the release date rather than the nature of the change: 2026.8, 24.04, 2026.08.1. It is common in operating system distributions, tooling with time-based release trains and products where the cadence matters more than the compatibility surface.
The trade-off is explicit and reasonable. You lose the ability to infer anything about breakage from the number, and you gain the ability to tell instantly how old a release is and whether you are behind. For an Ubuntu LTS, knowing that 24.04 was released in April 2024 tells you its support window immediately — far more useful in practice than knowing whether an API changed.
The trap is reading calendar versions with semantic instincts. A jump from 2025.12 to 2026.1 is one month of work, not a major release. Conversely, a calendar-versioned product can and does ship breaking changes in any release, because the scheme makes no claim either way. If a project uses calendar versioning, the release notes are not optional reading — they are the only source of compatibility information that exists.
Build identifiers: precise and unreadable
Build identifiers exist for machines. A Windows build number, an Apple build string, an Android build fingerprint — these are exact, unambiguous references to a specific artefact, and they are how support engineers and crash reporting systems identify what is actually running.
They usually sit alongside a marketing version, and the two are not redundant. Two devices reporting the same marketing version can be running different builds with different fixes, particularly where a vendor ships regional or carrier-specific variants. When something behaves differently on two machines that claim to be identical, the build identifier is usually where the difference is hiding.
For tracking purposes the rule is simple: record both, and never discard the build identifier because it looks like noise. It is the only field precise enough to answer 'is this the same software' definitively.
Security patch levels: a date that is not a release date
The most misread field in mobile and enterprise software is the security patch level. It looks like a date and it is a date, but it is not the date the update was installed or released. It states which monthly security bundle the device has received — meaning every fix published up to that point is present.
The distinction matters because patch level and version number move independently. A device can be two full feature versions behind and fully current on patches, or on the newest feature version with a patch level four months stale. Vendors ship these separately and device manufacturers add their own delay to the patch stream, which is why identical models on different carriers routinely report different patch levels.
Read it as a completeness claim rather than a timestamp: 'all published fixes through this month are applied'. A patch level from six months ago means six months of published, publicly documented vulnerabilities remain open on that device.
What to do with any version string you meet
There is a short procedure that works across all four schemes and takes about a minute.
First, establish which scheme is in use — the project's own contributing or release documentation says so, and if nothing says so, assume no promises are being made. Second, find the release notes for that specific version rather than the general changelog, because the general changelog frequently summarises several releases and drops the detail you need. Third, check whether a minimum requirement changed: runtime version, operating system floor, or peer dependency. That single line breaks more upgrades than actual API changes do.
Finally, record what you found alongside the version rather than only the version. Six months later the number on its own will tell you nothing, and the notes will have moved or been rewritten. A version number without its context is an identifier, not information — which is the entire argument for keeping a dated release record rather than relying on being able to look it up again later.
Categories this guide applies to
More guides
Building a Release Watchlist You Will Actually Read
Most tracking setups fail within a month for the same three reasons. A practical method for choosing what to watch, how to receive it, and what to deliberately ignore.
Release datesAnnouncement Is Not Availability
Hardware, games, films and physical products all have several release dates pretending to be one. Separating announcement, on-sale, ship and general availability makes a release calendar usable.
LifecycleEnd-of-Life Dates: The Deadlines Nobody Announces
Support windows, LTS branches and deprecation schedules are the only release events where nothing arrives to tell you they happened. How to find them and why they need to be stored, not read.