Tom MacWright

Optimistic and Pessimistic Versioning

GroupPessimisticvendoringnpm + strict dependenciesnpm + semverOptimistic

Modern software is defined by dependencies. The explosion of open source work and movement from batteries-included languages like PHP to minimal languages like JavaScript has meant that most applications, and indeed most libraries, require some other dependency. If it’s a web application, it’ll use a framework, included as a dependency. Or a database library, or so on.

Dependency culture has led to occasional panic, like left-pad, and thoughtful rants, like underscore’s versioning.

Having maintained distributed libraries and applications in Node.js with npm, as well as Python libraries and extensively tinkered with Go & vendoring, I think versioning can be thought of in terms of optimistic and pessimistic or trustful or guarded

Versions are social contracts about regressions and breaking changes

Semver standardized the meaning of a version number:

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

Along with this meaning, Semver gives you a set of symbols that lets you say, for instance:

The semver calculator is an interactive demo of these features. The implicit assumption is:

I completely trust the person who writes this code to do the right thing, to correctly version their project, and not introduce regressions or backwards-incompatible changes in minor or patch versions.


There are lots of ways for distrust to sneak into this system.

How much do these possibilities bother you? Should you try to avoid them always, or would you rather deal with them when they happen? Of course, they’re rare, but when they do occur, it’s bad news bears.

I think some rationale is:

Reflection in systems

As the chart at the top shows, I think three points on the continuum are:

Where I’m at

I’ve shifted from the npm default of saving dependencies with the ^ semver specifier to adding


To my ~/.npmrc file, so that whenever I run npm install somedep --save, it’ll pin the version of that new dependency. In some projects that are distributed as small modules, I’ve also started to tinker with versioning small dependencies, like in mapbox-sdk-js. For larger projects at Mapbox, like Mapbox Studio and Turf, we’ve also shifted to writing mono-repos rather than trying to make everything modules at the outset.

See also

August 23, 2016 @tmcw