Featured image from https://devopedia.org/semantic-versioning

When I started web development a long time ago, I heard about Semver (semantic versioning) as if it was some complicated jargon. But gradually I learned what it was and understood how relevant it was in web development, especially, when you rely on packages from a global package repository. I recently got asked by one my junior devs to explain it. I couldn’t explain it elegantly. So I decided to write a post.

Why versioning?

When you create a library or utility that is published on a public package repository, many people around the world may start using it without you even realising it.

Scenario 1

Let us say, you wanted to release improvements to your library, because after a couple of months, when you looked at your code, you realised that you could improve it, refactor it and even enhance it. You now have to make sure that you are releasing a new version, however, you also want to communicate that this new version might break those using the existing version of the library. How do you ensure that the users of your library understand this?

Scenario 2

Your library has a bug, someone has reported it to you and you checked the code, found that the fix was a one line change that had no impact on users who were currently using the library. Except for the fact that they wouldn’t run into the bug. How do you communicate that your bug fix will not require your library users to change their usage of your script?

Scenario 3

You have just identified that you could do what you were doing in your library, in a more efficient way and hence you have made some changes and decided, you want to release a new version. How do you communicate that this new version would be an improvement that wouldn’t require changes to the code of the users of your library?

Solution

The scenarios listed above are what Semantic versioning tries to resolve. Semantic - related to meaning. Versioning, the method of tracking increments of changes to a thing. Thus semantic versioning is a mechanism of conveying meaning to your software versions.

How?

A version in semantic versioning is expressed in the following format

x.y.z

  • x - Major version
  • y - Minor version
  • z - Patch version

Each of the parts separated by the dots convey a special meaning to the version. All the parts are expressed in integers. In semantic versioning, the numbers are not like a unit of measurement where when y goes over a point, x automatically gets incremented. So keep that in mind.

Imaginary library for example

Alright, you’ve come this far, let us take a look at it through a concrete example:

Say that your package is on the following version.

1.3.0

User987 has now reported a bug on github that you decided to look at. You found out that the fix was easy and requires no effort on the users part to change the way they use the code. How do you convey this?

Patch

Bug fixes are released as a patch version increment. So in your case, as explained above, your new version would be:

1.3.1

And any further bug fixes to that version, would just result in more increments of the **_patch _**part of the version, unless it results in a situation where the library users would have to change the way they currently use your library methods. In other words, no breaking changes, changes are backwards compatible, and is only a bug fix.

Minor

Let us say after a couple of months, you encounter a scenario like the one mentioned in Scenario 3. This is where you want to convey to your users that your new version of the library, is simply a bunch of enhancements that do not require them to change the way they are using your library, but still gives them plenty of additional stuff to use. It might be new methods, it might be performance improvements, or just optional extras. So in that case your new version would be:

1.4.0

A minor version upgrade. In other words, no breaking changes, hence code is backwards compatible

Major

You and your mates are into something big. You have re-architected your library and refactored old code and done a lot of hard work, in improving the way your library can be used. However, in the process, you have now introduced some changes which would mean, your users, would have to refer to methods differently, pass in a different set of arguments, initialise something differently etc. In other words, there are breaking changes.

In this case, you’d communicate this information to your users, using a major version increment. So your library’s new version would now be:

2.0.0

How do users specify what versions to use to their package manager?

Semantic versioning not only lets package writers communicate version information to users, but also lets users to choose versions, by restricting upgrades in their local file where they specify dependencies, like the "dependencies" section in package.json or in "packages.config" in nuget world or some other file, that I have never used.

Stick to patch version upgrades

Sometimes as a library user, you just want to be extra cautious and hence only want your package manager to update your packages to the latest patch version updates. You can do this by specifying a tilda(~)

"packageName": "~1.3.0"

If that was in your package.json’s dependencies section, then whenever, you were running an npm install, it would only ever install a more recent patch version of that package, and avoid any further updates.

Could loosen up to minor version upgrades

This time you have been using a library for a pretty long time and you trust the publishers to adhere to the code of semantic versioning. So you don’t really mind a minor version update.

You can specify this in your package.json for example, using a caret symbol (^):

"packageName": "^1.3.0"

This way, when running npm install, npm would not hesitate to download a minor version update to your local version of the said package. This means, it would automatically pick patch version updates and minor version updates.

Alternative?

A lot of web developers I have worked with, including myself, often end up wondering “what did the caret syntax mean again?”. It could be that or patch version. There is an alternate way to specify the same thing to your package manager.

1.3.x

tells nppm to use patch updates only.

1.x

tells npm to choose: minor and patch updates please.

What if I can’t remember either?

Checkout this useful npm repository page: https://semver.npmjs.com/

It lets you type in a certain semantic version range in the syntax mentioned earlier and highlight, what the range would be.

versioning
1.x would mean, all minor and patch versions till the next major version

Similarly giving something like ~2.4.0

2.4.0
~2.4.0 means, only patch upgrades from 2.4.0

Other ways

You can specify ranges of versions you are willing to update to in your package.json, in some other elaborate ways too. They can all be viewed at the bottom of the https://semver.npmjs.com/

I hope that was helpful. I know, I have mostly used npm as an example. However, this applies to any package manager that respects sematic versioning.

Happy versioning