The most important (and most overlooked) element in versioning is defining the scope of the version. For example are “under the hood” database schema changes part of the version, or a file system layout? or in your case the ABI.

In my organisation we would increment the patch version in this instance as we consider bugs (such as security vulnerabilities) inherited from dependencies to be bugs in the application itself.

Various Implementations:


Given a version number MAJOR.MINOR.PATCH, increment the:

  • MAJOR version when you make incompatible API changes,
  • MINOR version when you add functionality in a backwards compatible manner, and
  • PATCH version when you make backwards compatible bug fixes.

What about backwards incompatible bugfixes?

Trust your heart; but if you choose wrong, everyone will hate you forever.

My thoughts: View this from the perspective of a user. “Will silently keeping this bug in my code hurt worse than being forced to upgrade?” Secondly, “is there anything I can do to mitigate the upgrade cost and/or the cost of keeping the bug in a backwards compatible way?” If so, you don’t have to worry about whether or not to bump the patch or the major version.

  • safety related bugs: force the upgrade
  • correctness/performance related bugs: don’t force
    • Why? If keeping the code would hurt, they would’ve noticed already
    • People don’t ship incorrect code on purpose; if they use buggy code they probably aren’t hitting the edge cases where the buggy behavior shows
    • Bugs vs features is sometimes a very thin line

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

What do I do if I accidentally release a backwards incompatible change as a minor version?

Bump the minor version with a revert. If it’s appropriate, document the offending version and inform your users of the problem so that they are aware of the offending version. This relies on a package manager that has a “always latest patch” resolution strategy.


Naming different versions different package names

    • ugh. Always select the oldest version.
    • Helps with one type of problem, introduces another.
    • I disagree with some of the conclusions, but the problem presented is deeply compelling and the reflection on the social implications of semver major version bumps is worthwhile to think about.
    • Forcing different package names instead of major version bumps is a more effective way to get people to create packages that play together nicely inside an ecosystem.
    • Rather than making a new package name, just add the major version as a sub-path. Then you don’t need new names for things.
    • very similar to “eternal compatibility in theory”
    • big problem: code isn’t wrong, its just different.
  • append-only codebases where you only add functionality and changing the meaning of a function means just duplicating it + renaming rather than breaking compatibility.
    • Works well with functional programming, newtype patterns, etc.
    • But don’t fear the refactoring either…
  • Think about how to automate churn related changes with wrappers, fixers, code mods, etc.

All of the cabal files that I’ve seen so far seem to specify source-repository head as just the git repo. I’ve never actually seen anyone use this; although this can also point to a tag, which is not immutable, so it can be freely updated in master and then that targeted commit can be tagged.

Is there anything wrong with moving the tag should a small critical fix be needed in a short timeframe?

If there’s not a fix that’s needed after a while, a branch could always be created off of the tag and then committed to.

Is there any difference between

master has version 0.5.99 until the release, then create a release branch for 0.6, set the version, then set master to 0.6.99. And the next subsequent commit contains a critical fix that was intended to be in 0.6


A commit that sets the version to 0.6, and one after that to fix something critical before the release

And, honestly, I’m suspecting that the desire to add some extra manual process to slow down releases might stem from a desire to have vX.0 be “perfect” and avoid nearly-immediately releasing patch releases?

My attitude toward versions (which I have often failed to live by) is that the only time something should have a version that could possibly correspond to a real release is exactly when that release happens.