Alternative Versioning
Summary
The version number is composed of three parts: BRAND, NEW, and CARE.
Increment BRAND when you make something extraordinary, usually with breaking changes. Increment NEW<br>when you add exciting new functionalities (including breaking changes with an easy upgrade path). Increment<br>CARE version when you make backward compatible bug fixes and improvements.
Essentially, AltVer is SemVer but explicitly acknowledges that small breaking changes can live in minor versions<br>when the impact is minimal and the upgrade is easy.
Just like SemVer, additional labels for pre-release and build metadata are available as extensions.
Motivation
After over a decade of using and maintaining open source, I’ve come to believe SemVer made everybody terrified of new major versions.
On one hand, most library users lock their dependency manager to the latest minor version (i.e. the latest released right before the next major).
On the other hand, most maintainers are hesitant to tag a major version because it will partition the community.
In the wild, many projects are actually versioned with AltVer without naming it. Maintainers often balance the pros and cons for each change and might introduce "a breaking change" in a minor (or patch) version.
Understanding what a breaking change is
When I discovered SemVer, I thought this was very scientific and everyone always agrees on what a breaking change is. Unfortunately, it’s a lot more subtle than that.
Example 1: Empty results
A function get_users() returns null when no users are found, but the docs say it should return []. Users have written if (result === null) checks everywhere. Fixing it to return [] breaks their code, but new users see it as an obvious bug fix.
Example 2: Date formatting
A function format_date() returns "DD/MM/YYYY" but the docs say "MM/DD/YYYY". European users built their apps around this behavior. American users file bugs constantly. Fixing it is a "bug fix" for Americans and a "breaking change" for Europeans.
Example 3: Case sensitivity
A search function is supposed to be case-insensitive but accidentally matches case-sensitively. Some users rely on this to filter results precisely. Fixing it changes what their searches return.
Hyrum’s Law
This ambiguity is well captured by Hyrum’s Law:
With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.
No matter how well you document your API, users will depend on behaviors you never intended to guarantee. Every bug fix risks being someone else’s breaking change. The xkcd comic "Workflow" illustrates this perfectly:
People consider things to be a bug fix or breaking change depending on how it affects them.
The consequences of a Breaking Change
Whenever a breaking change is released, you’d increase the major version number. Major versions are well named: MAJOR means it’s important and significant, so it should be rare.
Delayed release
As a user, you don’t expect a major version every few weeks. So breaking changes are bundled and the fix is delayed. Instead of getting an important fix now, you’ll get it "next time".
One solution is sometimes to run a fork of the dependency until the next release.
Partitioning user base
Most users upgrade to the latest minors but won’t update often to the next major (unless you’re an important part of the stack). If you’re a small dependency, users won’t upgrade until they need to. It’s fine! But now as a maintainer you have users using multiple major versions (sending reports, feature requests and so on).
This creates real problems:
Ecosystem fragmentation : Plugins, extensions, and tutorials target specific major versions. The community splits.
Backporting burden : Security fixes and critical bugs need to be applied to multiple major versions. This multiplies the maintenance work.
Fragmented documentation : Users reading the docs might be on v2, v3, or v4. Again, this adds maintenance work.
Confusing discussions : Bug reports, Stack Overflow answers, and GitHub issues become a mess. "Did you try X?" "That doesn’t exist." "Oh, you’re still on v2?"
The more major versions you release, the thinner you spread the community.
Trust the maintainer
Maintainers are always responsible for what gets into the release. They will carefully weigh if something needs to be fixed with or without breaking changes, when it should be released, and what the version type should be.
Maintainers need to keep things manageable for them so you get new features and bug fixes.
Maintainers will always avoid breaking things and upsetting the people trusting them with their code.
Mistakes happen. It happens to all of us but generally, you should trust the maintainer.
AltVer is a statement that maintainers will do their best to balance all the project stakes. Trust the maintainer.
Specification
Any new BRAND version must be exciting! The...