0

Semantic Versioning Explained: How MAJOR.MINOR.PATCH Works

If you have ever updated a library, a plugin or a business tool and wondered whether the new version might break something, the version number was trying to tell you. Semantic versioning, usually shortened to SemVer, is a widely used convention that gives each part of a version number a specific meaning. Once you know the rules, a number like 2.7.1 stops being decoration and becomes a small piece of risk information.

This guide walks through what the specification says, how versions are compared, and how to use that knowledge when you evaluate or update software. It is written for developers, but it is just as useful for the people who buy, approve and maintain business software and need to judge how risky an upgrade is.

What semantic versioning is

Semantic versioning is a specification, published at semver.org, for numbering software releases so that the number communicates the kind of change. A version takes the form MAJOR.MINOR.PATCH, for example 3.2.14. Each part is a non-negative integer, and numbers do not carry leading zeroes.

The specification's core idea is that a project declares a public API (the set of functions, endpoints, commands or behaviors other software relies on) and then changes the version number according to what happened to that API. The API can be described in code or in documentation; what matters is that it is clear enough for users to depend on.

The three numbers

The specification defines what to increment in each situation:

  • MAJOR goes up when you make incompatible changes to the public API. Code that worked against 2.x may not work against 3.0.0 without changes.
  • MINOR goes up when you add functionality in a backward-compatible way. Moving from 2.4.0 to 2.5.0 should not break code that worked before.
  • PATCH goes up for backward-compatible bug fixes. The specification defines a bug fix as an internal change that fixes incorrect behavior.

When a higher number increases, the lower numbers reset to zero. A breaking change on version 2.5.3 produces 3.0.0, not 3.5.3. A new backward-compatible feature on 2.5.3 produces 2.6.0.

What a reader can infer

For anyone deciding whether to update, the convention gives a rough decision guide:

Change in version What it signals Typical caution level
2.5.3 to 2.5.4 Bug fixes only Low: read the notes, test briefly
2.5.3 to 2.6.0 New features, existing behavior intact Moderate: test the areas that touch the library
2.5.3 to 3.0.0 Incompatible API changes Higher: plan time to read the changelog and adjust code

This is a guide, not a guarantee. SemVer is a promise made by the project's maintainers. Maintainers can misjudge what counts as a breaking change, and a "patch" can still affect something you happened to rely on. Treat the number as a prompt for the right amount of testing rather than a substitute for it.

Version 0.y.z: initial development

The specification reserves major version zero for initial development. In its words, anything may change at any time, and the public API should not be considered stable. If a tool is at 0.9.2, the maintainers are saying the interface is still being worked out, and a 0.10.0 release could change behavior that 0.9.2 had.

Version 1.0.0 is where the specification says the public API is defined. After 1.0.0, the numbering rules above apply to how that API changes. When you are comparing two tools for a business-critical job, a project that has reached 1.0.0 and keeps its changes tidy is communicating a commitment that a long-running 0.x project is not (although some 0.x projects are stable in practice, so check the project's own statements).

Pre-release versions

A pre-release is marked by appending a hyphen and a series of dot-separated identifiers, such as 1.0.0-alpha.1 or 2.3.0-rc.2. The identifiers may use only ASCII letters, digits and hyphens, they cannot be empty, and numeric identifiers cannot have leading zeroes.

The key rule is precedence: a pre-release version has lower precedence than the normal version it leads up to. So 1.0.0-alpha comes before 1.0.0.

Common labels such as alpha, beta and rc (release candidate) are conventions that teams use inside this structure; the specification defines the syntax and ordering, and projects decide what each label means for them.

Build metadata

Build metadata is appended with a plus sign, for example 1.0.0+20130313144700. Its identifiers are dot-separated, use only ASCII letters, digits and hyphens, and cannot be empty. It differs from a pre-release tag in one significant way: build metadata must be ignored when determining version precedence. That means 1.0.0+a and 1.0.0+b are considered to have the same precedence. Build metadata is useful for recording something like a build timestamp or a commit identifier without changing how versions sort.

How versions are compared

The comparison rules are mechanical, which is why tools can apply them automatically:

  1. Compare MAJOR, MINOR and PATCH numerically, from left to right. Numeric comparison matters: 1.10.0 is higher than 1.9.0, even though "1.9" might look larger when read as text.
  2. If the three numbers match, a version with a pre-release tag is lower than the same version without one.
  3. When both have pre-release tags, compare the dot-separated identifiers from left to right. Numeric identifiers are compared as numbers, identifiers with letters are compared in ASCII order, numeric identifiers rank lower than text identifiers, and if all earlier identifiers match, the longer set ranks higher.
  4. Ignore build metadata.

Following these rules, the sequence 1.0.0-alpha, 1.0.0-alpha.1, 1.0.0-beta, 1.0.0-beta.2, 1.0.0-beta.11, 1.0.0-rc.1, 1.0.0 is in ascending order.

Deprecation and removal

Software does not usually jump straight from "supported" to "gone." The specification says that when you deprecate functionality in the public API, you should increase the minor version. Its FAQ advises a two-step approach: update the documentation to announce the deprecation, then ship a new minor release that contains it. Removal of the deprecated feature should wait for a later major release, after at least one minor release has carried the deprecation, so users have a chance to adapt.

For a team maintaining software, this suggests a practical habit: search the release notes of your dependencies for the word "deprecated" whenever you see a minor update, because that is when the specification asks maintainers to start warning you.

Using SemVer when you choose or update software

Here are some practical ways to apply the convention:

  • Pin with intent. Some package managers let you allow only patch updates or patch and minor updates automatically; npm, for example, uses a tilde range such as ~1.0.4 for patch releases and a caret range such as ^1.0.4 for minor releases. Allowing patch updates and reviewing minor and major ones is a common approach, though the right policy depends on your testing capacity.
  • Read the changelog on a major bump. A new major version is the maintainers' way of saying "something here is incompatible." Allocate time to read what changed before you schedule the upgrade.
  • Be cautious with 0.x dependencies. Because anything may change at any time, lock to exact versions and test every update.
  • Check the project's own practice. SemVer only works if maintainers follow it. A look at a few past releases and their notes will show whether the numbers have matched the changes.
  • Do not confuse version numbers with marketing names. Some projects use calendar-based versioning (CalVer), such as Ubuntu's year-and-month numbers, and those numbers do not carry SemVer's meaning. If a vendor does not state that it follows semantic versioning, do not assume it does.

Common misunderstandings

"A higher number is always better." A higher version is newer, not automatically better for your use. A major release can require changes on your side.

"The patch number means small." It means backward-compatible fixes, which the maintainers believe will not alter documented behavior. The size of the change in lines of code is irrelevant.

"SemVer prevents breakage." It communicates intent. Tests, staging environments and rollbacks are still how teams protect themselves.

Summary

Semantic versioning gives MAJOR.MINOR.PATCH a clear meaning: incompatible changes, backward-compatible features, and backward-compatible fixes. Pre-release tags mark unfinished builds and sort below the final release, build metadata is ignored when comparing, and 0.y.z signals that the interface is still unsettled. Understanding these rules lets you read a version bump as a risk signal and plan updates sensibly, whether you write code or manage the tools your business runs on.

Sources

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *