Software Versioning with SemVer

Posted on 12 Aug 2015 by Steven Lamerton


When releasing software, either directly to end-users or as a library, it is convention to supply a version number. As there is no universal standard which defines version numbers is it not always clear how to calculate the number for a particular release. One approach is to use Semantic Versioning, also known as SemVer, which is used by a number of high profile codes including the Ruby programming language.

Semantic Versioning

Semantic Versioning uses a relatively simple scheme to determine which version number should be attached to the next release of your software. For full details see their website, but in summary:

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.

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

Using Semantic Versioning

Although Semantic Versioning is defined in terms of an Application Programming Interface (API) it can easily be applied to any kind of software interface. If you are writing a library it is simple, your API is the set of functions and routines that your libraries exposes for use by your end users. Imagine the following library in C, which we will call libmultiply, currently at version 1.0.3.

// Multiplies the given value by two
int multiply_by_two(int val) { return val + val; }
// Multiplies the given value by three
int multiply_by_three(int val) { return val * 3; }

Updating multiply_by_two to read return val * 2 would be a backwards compatible bug fix and so only require an increment of the patch version, giving a new version of 1.0.4. Adding a new function, such as multiply_by_four would be a backwards compatible change to the API and so require an increment of the minor version to give 1.1.0. Removing all of the functions and replacing them with a new function int multiply(int a, int b) { return a * b; } would be a breaking change and the version would be bumped to 2.0.0.

We can apply similar logic to other kinds of interface, such as configuration files or a command line interface. For example imagine a command line interface for a basic data processing tool:

./process --inputfile=in.dat --format=csv|tsv

If there are internal bug fixes to the software then the patch version should be incremented. If we add a new supported format then it would be a minor version update, existing scripts which call the interface will still work but there are new features available. Finally if we remove the --format option, perhaps because we now auto-detect using the input filename then it would be a major version increment, existing users will have to change their scripts / behaviour.

What are the advantages?

Using Semantic Versioning has two main advantages. Firstly it provides a clear set of rules for generating version numbers. Secondly, and more importantly, it gives users of the software a method to reason about the nature of the changes and how it will impact them. Upgrading after a patch or minor version change should be straightforward as it will not break existing code. In the case of a minor change it is worth checking the documentation as there may be new features which will aid the user. In the case of a major version change however the user knows to allow extra time for the upgrade as there is the possibility of breaking changes.

Summary

Semantic Versioning is a way of versioning your software that aims to give more meaning and use to the version number and it can be applied to a wide range of software, not just libraries. Should you have any questions or suggestions, either about the article or more generally, please contact us.