Semantic Versioning definition
Semantic versioning (SemVer) is a convention for numbering software releases as MAJOR.MINOR.PATCH, where each part signals the kind of change. A major increment means breaking changes, a minor increment adds backward-compatible features and a patch fixes bugs without changing behavior. It lets developers and package managers judge upgrade risk at a glance.
How MAJOR.MINOR.PATCH works
Take a library at version 2.4.1. Fixing a bug without changing its public interface produces 2.4.2. Adding a new, optional function produces 2.5.0, with the patch number reset. Removing a function, renaming a parameter or changing a default behavior that existing code relies on produces 3.0.0. The rules apply to the public API, so the first step in using SemVer is being clear about what that API is.
Versions below 1.0.0 are a special case: anything may change at any time, which is why young projects often stay on 0.x while their interface settles. Pre-release labels such as 2.0.0-beta.1 and build metadata such as 2.0.0+build.45 extend the format, and tags in version control, such as v2.4.1 in Git, mark the exact commit behind each release.
Version ranges in package managers
Package managers use SemVer to decide which updates are safe to install automatically. In npm, a caret range such as ^2.4.1 accepts any 2.x.x version at or above 2.4.1, trusting that minor and patch releases are compatible, while a tilde range such as ~2.4.1 accepts only patch updates. Lock files such as package-lock.json or pnpm-lock.yaml then pin exact versions, so every developer and CI build installs the same dependency tree.
Tools like Dependabot and Renovate read these ranges to open update pull requests, often grouping patch updates and flagging major ones for review. Automated tests in a CI/CD pipeline are what make accepting frequent minor and patch upgrades safe in practice.
Versioning APIs and apps
Web APIs borrow the same idea. Breaking changes, such as removing a field or changing its type, get a new major version, often in the URL (/v2/orders) or a header, while additive changes ship without one. Running two major versions side by side for a deprecation period gives clients time to migrate. Designing REST APIs so new fields are optional keeps most changes non-breaking.
Mobile apps also carry version and build numbers in the App Store and Google Play, but users rarely treat them as a compatibility signal. For apps, the critical versioning is on the backend API, because old app versions stay installed for months and must keep working.
Common SemVer mistakes
SemVer only works when maintainers follow it honestly and consumers understand its limits. Most version-related breakages trace back to one of these mistakes rather than to the scheme itself, and all of them are avoidable.
A useful habit is to write the changelog entry before the code is merged. If the entry has to tell callers they must now do something differently, the release is a major version, whatever the size of the diff. The common mistakes are:
- Shipping breaking changes in a minor or patch release because the change seemed small
- Treating a 0.x library as stable and accepting every update automatically
- Forgetting that behavior changes, not just signature changes, can break callers
- Never releasing 1.0.0, leaving users unsure what is stable
- Skipping changelogs; Conventional Commits and semantic-release can generate them and choose the next version automatically