To Pin or Not To Pin the Version

Version pinning has become common practice and it usually seen as the way to go. This post highlights some of the benefits and issues with version pinning and highlights benefits of not pinning the version of dependencies only as required as a potential alternative.

The benefit of pinning versions of dependencies is that development can keep going without getting interrupted by the changes of dependencies which break your code.

The above has insight in that pinning versions makes it easy for development teams to develop based on outdated dependencies that don’t incorporate the latest and greatest from the authors of their dependencies. In other words, it is a path to become that project which is still running version 2 of Python even though it was end of life in 2020.

There is also a case to pin dependencies so that production deployments keep working. When deploying a container to production (or other artefact), ideally the dependency versions used to test that container match what is deployed in production. There is an alternative to getting this benefit – deploy the container image using the same image that was built during testing. That way, that container will keep working without a dependency pin even if there is a new version of a dependency.

Another argument for dependency pinning is that there are tools, like depandabot on GitHub and similar tools, which can upgrade versions for you. That is a lot of busy work of accepting PRs from the bot whenever there is a new minor or even patch version of a dependency which can get quite cumbersome as either the number of projects or dependencies grow. Whilst those PRs can get auto-merged if the tests pass, there are risks with having code get modified without a human in the loop, especially for critical projects.

So what is the alternative? Well, don’t pin dependencies. But doesn’t that mean that when a new major version of a dependency is released, development could be interrupted with a breaking change? Yes, and this is healthy as it is a good opportunity to review the new changes from the dependency and make the necessary changes to be able to use it. That way the project stays up to date with the latest and greatest version of dependencies and the team has an automated way of being informed there is an upgrade for a dependency.

The argument to pin major version is stronger than pinning all the way down to the patch version. It means that upgrades among major versions can be planned and executed because there can be significant changes between major versions requiring substantial effort to be able to use the major version. Instead of proactively pinning, this can also be achieved by reactively pinning if this situation is found and then adding a task for the team to perform the upgrade and remove the pin again.

Another argument for pinning past the major version to, for example, the minor version is that not all projects are disciplined or skilled enough (or decide to anyway) not to introduce breaking changes on minor versions. This again can be addressed by reactively pinning. In these cases, it is also worth considering whether the dependency is still needed and of high enough quality.

To summarise, proactively pinning is either makes it easy to ignore new versions of dependencies or introduces a lot of busy work keeping dependencies up to date. A great alternative is not to pin the version of dependencies unless it is needed to address an issue, such as a major version requiring substantial development effort to be adopted. Outside of those cases, without version pins, the team will automatically make use of the latest and greatest dependencies have to offer and the team doesn’t have to think about the version of dependencies.

Leave a comment