Code & Dev
Free Semantic Version Comparator Online
Compare two semver version strings. Check if one is greater, equal or less. Validate semver format.
What is semantic versioning and why was it created?
Semantic Versioning (semver) is a formal specification for version numbers that encodes meaning about the nature of changes between releases. It was created by Tom Preston-Werner, co-founder of GitHub, to solve a fundamental problem in software dependency management: "dependency hell" — the situation where upgrading one package breaks another because version numbers carry no reliable information about compatibility.
Before semver, version numbers were largely arbitrary. One library might use dates (20240115), another sequential integers (42), another internal codenames (Bionic Beaver). Package managers could not reason about compatibility, so developers either pinned to exact versions (missing security fixes) or used wildcards (risking breakage from major changes).
Semver's insight is simple but powerful: version numbers are a communication contract between library authors and their users. A version bump from 1.2.3 to 1.3.0 explicitly promises backward compatibility. A bump to 2.0.0 explicitly warns of breaking changes. This shared language allows package managers to automatically determine safe upgrade ranges.
The semver specification — MAJOR.MINOR.PATCH rules
A semver version number has exactly three numeric components separated by dots. Each component has a precise rule for when it must be incremented:
- Removing a public function or method
- Changing a function signature (adding required parameters)
- Changing the return type of a function
- Renaming a public class or module
- Changing behavior that existing code depends on
When major is incremented, minor and patch are reset to zero. 1.4.7 → 2.0.0. Major version 0 (0.y.z) is special: anything may change at any time.
- Adding new public functions or methods
- Adding new optional parameters with defaults
- Adding new endpoints to an API
- Adding new config options
- Deprecating functionality (but not removing it)
When minor is incremented, patch resets to zero. 1.4.7 → 1.5.0. Existing code continues to work without modification.
- Fixing a calculation error
- Fixing a crash or null pointer exception
- Fixing a security vulnerability
- Improving performance without changing the API
- Fixing incorrect documentation
Patch fixes must not change public API behavior in any observable way. If the fix requires an API change, it is a minor or major bump.
Pre-release versions and build metadata
Semver supports two optional extensions beyond the three-part version number. Both are appended to the base version:
1.0.0-alpha 1.0.0-alpha.1 1.0.0-0.3.7 1.0.0-beta.11 1.0.0-rc.1
Pre-release versions indicate the release is unstable. They have lower precedence than the associated normal version: 1.0.0-alpha < 1.0.0. Dot-separated identifiers are compared left to right. Numeric identifiers are compared numerically; alphanumeric are compared lexically. Numeric identifiers always have lower precedence than alphanumeric: alpha.1 < alpha.beta.
1.0.0+build.1 1.0.0+20240115 1.0.0-beta.1+sha.0e3ab4f 1.0.0+exp.sha.5114f85
Build metadata is for identifying specific builds — CI run numbers, commit hashes, timestamps. Critically, build metadata is IGNORED when determining version precedence. 1.0.0+001 and 1.0.0+20240115 are considered equal. Build metadata may appear after either the patch version or after a pre-release identifier.
1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0How package managers interpret semver ranges
Package managers extend semver with range syntax that allows specifying acceptable version ranges rather than a single version. Understanding these operators is essential for reading and writing package manifests.
| Operator | Example | Equivalent range | npm / Cargo / pip |
|---|---|---|---|
| ^ | ^1.2.3 | >=1.2.3 <2.0.0 | npm default — safe minor/patch updates |
| ~ | ~1.2.3 | >=1.2.3 <1.3.0 | npm — patch updates only |
| >= | >=1.2.3 | >=1.2.3 | Any version at or above |
| > | >1.2.3 | >1.2.3 | Strictly above (not including) |
| = | =1.2.3 | 1.2.3 exactly | Exact pin (also written as 1.2.3 in npm) |
| x / * | 1.x | >=1.0.0 <2.0.0 | Wildcard: any minor/patch |
| range | 1.2.3 - 2.3.4 | >=1.2.3 <=2.3.4 | Inclusive range |
| || | ^1.2 || ^2.0 | ^1.2 OR ^2.0 | Union of ranges (npm) |
Rust's Cargo treats 1.2.3 (without a prefix) the same as npm's ^1.2.3 — allowing compatible updates. Python's pip uses == for exact pins and ~= for compatible releases. Go modules use semver with a /vN suffix for major versions above 1 (e.g., github.com/pkg/v2).
Semver in practice — when to bump major vs minor vs patch
Semver anti-patterns to avoid
The most damaging anti-pattern. Users who run npm update expecting safe updates suddenly have broken code. Always make breaking changes in major releases, even if they seem small.
Some teams avoid major version bumps to hide the existence of breaking changes, hoping no one notices. Proper semver requires honest signaling — if it breaks, it's a major.
Version numbers must be incremented sequentially. Skipping versions creates confusion in changelogs and for package managers. Release 2.0.0 even if it's going to be short-lived.
Staying on 0.x.x indefinitely is a red flag — it signals the API is never stable. When your library has a stable, committed public API, release 1.0.0 and honor the semver contract.
Documentation changes, README updates, and CI config changes don't affect the package's behavior and don't need a version bump. Only functional code changes to the library's behavior warrant a new release.
Semver signals the type of change, but users need to know what actually changed. A machine-readable changelog (CHANGELOG.md following keepachangelog.com format) is essential for maintainable dependencies.
Breaking change detection in practice
Manually reviewing every change for breaking behavior is error-prone. Several tools exist to automate breaking change detection:
A commit message convention that encodes the change type: feat: for features (→ MINOR), fix: for bug fixes (→ PATCH), and feat!: or BREAKING CHANGE: footer for breaking changes (→ MAJOR). Tools like semantic-release parse these commits and automatically determine the correct semver bump and generate changelogs.
Microsoft's API Extractor tracks the public API surface of TypeScript packages. It generates an .api.md file that can be committed and diff'd in CI to detect API surface changes, making breaking changes visible in code review.
Go's official tool for detecting API incompatibilities between versions of a Go module. It compares the exported identifiers of two versions and reports any removals or incompatible changes.
Analyzes your Git history using Conventional Commits and suggests the next semver version. Integrates with CI pipelines to automate the release process entirely.
FAQ
Common questions
What is semantic versioning?
Semantic versioning (semver) is a versioning scheme that uses a three-part version number: MAJOR.MINOR.PATCH. MAJOR increments for breaking changes, MINOR for new backward-compatible features, and PATCH for backward-compatible bug fixes. It was created by Tom Preston-Werner (co-founder of GitHub) and is specified at semver.org.
When should I increment the major version?
Increment the major version when you make incompatible API changes. Examples: removing a public function, changing a function's signature, renaming a public class, changing the behavior of an existing feature in a way that breaks existing code. Major version 0 (0.y.z) is for initial development — the public API is not yet stable and anything may change.
When should I increment the minor version?
Increment the minor version when you add new functionality in a backward-compatible manner. Examples: adding new public functions or methods, adding new optional parameters, adding new endpoints to an API. Existing code that uses the library continues to work without modification.
When should I increment the patch version?
Increment the patch version when you make backward-compatible bug fixes that do not change the public API. Examples: fixing a calculation error, fixing a crash, improving performance without changing behavior. If you release a patch, reset the patch number and bump minor: 1.4.2 → 1.5.0, not 1.4.3.
What are pre-release versions?
Pre-release versions have a hyphen suffix: 1.0.0-alpha, 1.0.0-beta.1, 1.0.0-rc.2. Pre-release versions indicate instability and have lower precedence than the release version: 1.0.0-alpha < 1.0.0-beta < 1.0.0. Numeric pre-release identifiers are compared numerically (alpha.1 < alpha.2 < alpha.10), while alphanumeric identifiers are compared lexically.
What is build metadata in semver?
Build metadata is appended with a plus sign: 1.0.0+build.20240115. Build metadata is ignored when determining version precedence — 1.0.0+001 and 1.0.0+20240115 are considered equal. It is used to identify specific builds (CI run IDs, commit SHAs, build timestamps) without affecting version ordering.
What do npm semver range operators mean?
npm supports these range operators: ^ (caret) allows minor and patch updates within the same major (^1.2.3 = >=1.2.3 <2.0.0). ~ (tilde) allows only patch updates (˜1.2.3 = >=1.2.3 <1.3.0). >= allows any version at or above the specified. * or x is a wildcard matching any version. 1.x.x = any minor/patch of major 1.
Does 0.x.x mean the same as 1.x.x?
No. Major version zero (0.y.z) is a special case in semver: the public API is considered unstable and anything may change at any time. A 0.y.z → 0.y+1.z change may contain breaking changes even though only the minor version was bumped. Production dependencies should typically use versions >= 1.0.0 where the stability guarantee applies.
Is my version string valid semver?
A valid semver version matches: MAJOR.MINOR.PATCH where each part is a non-negative integer with no leading zeros, optionally followed by a pre-release suffix (-alpha.1) and/or build metadata (+001). Examples: 1.0.0 ✓, 1.0.0-alpha ✓, 1.0.0-alpha.1+build ✓, 1.0 ✗ (missing patch), 1.0.0.0 ✗ (too many parts), 01.0.0 ✗ (leading zero).
More in Code & Dev