Incrementing package version number between releases

Is there an established best practice for when to bump the version number between releases? Say I just released 1.0.0 and that’s what’s in the HEAD of main in Project.toml. Now I start a branch to develop some feature. It feels to me like one should increment the version number right there, to indicate that this is not 1.0.0, but something beyond, i.e. 1.1.0 for a new feature, 1.0.1 for a bugfix, 2.0.0 for a breaking change. And maybe with the suffix -dev or something which if I’m not mistaken Pkg basically ignores, but is a helpful indicator. I was surprised not to find anything addressing this when I searched, at least nothing recent (Pkg3) though I may just not be using the right keywords.

(/me does a bit more Googling…)

Ah, it’s addressed in the colprac for DifferentialEquations.jl and it seems they follow more or less what I’m describing. Given the prominence of that package I’ll assume it’s a good model to follow, though if there are other viewpoints those would be nice to hear too.

Julia recommends semver

1 Like

Is that needed? I believe people just develop on main branch (some still call it master). You can get that latest moving-target version, or any arbitrary commit.

You tag a new release when it’s useful for others, with a new updated version number. I’m not sure why you would tag unhelpful releases with a version number. It’s not like people can’t check out any arbitrary commit, or use the main branch, though then knowing possible risks.

I hadn’t seen -dev, or -DEV (is upper case preferred, I don’t think it really matters?) used (much) but after writing the above I do see:

If the repository is in a state where there are unreleased changes for an extended period of time in preparation for a release, then the version in the Project.toml should be set to the version number of the intended release, with the -DEV suffix.

My thoughts on the matter from when I was working a lot with Python: Inter-Release Versioning Recommendations - Michael Goerz

All of that still applies to Julia as well: basically, add a +dev or -dev suffix to the version number between tagged releases.

The one small refinement I’ve adopted is that I started to use -dev much more than +dev these days and use it to keep track of whether a pull request is major, minor, or bugfix: I’ll set the version to “whatever the version would be if this were released right now”, with the added -dev suffix. I might still use +dev if immediately after a release I’m fixing some typos in the documentation, or tweak a CI script, or something like that.

I’m actually very strict about this in my own projects: every commit that is not a tagged release must have a -dev or +dev suffix. This is enforced via CI.

I’m of the opposite position. I consider juggling with inter-release version numbers to be pointless busy-work.


I’m interested @GunnarFarneback to know more about your process.

My inter-release version philosophy has grown out of the experience of managing several projects in computational research groups for over a decade. More than once, there’s been problems with “less organized” people using non-tagged versions in their HPC jobs (and then later being unable to reproduce their results). Since the version numbers show up in the logs on the cluster, having dev suffixes serves as an easy and invaluable red flag in such cases.

In the other direction: I develop several inter-dependent packages that I routinely test against each other, both with the master branch of all packages, and in various combinations of master/released versions. It is pretty essential for me to be able to easily keep track of whether I currently have a package dev-installed or not.

Version is bumped in some commit in a feature branch. Whenever a new version number is merged into master, that revision is automatically registered by CI.

When it comes to tracking use of versions between releases I’ve found Manifest.toml sufficient for that but I guess it also helps that our deployment environment doesn’t have credentials to the package repositories but has to obtain released packages through an internal package server.


Making a release every time a PR is merged is a good workflow! It implies that there is never any inter-release commit on master, though. If you stick to that, the question of how to set versions between releases doesn’t really come up. Assuming people aren’t checking out random intermittent commits from PR-branches, at least.

1 Like

In our experiment we use the version formatting which is similar to the output of git describe in the provenance tracking, which is implemented both externally when running tens of thousands of jobs on multiple clusters (via workflow managers) and also internally in our base frameworks, which are implemented in multiple languages and write a big variety of (partly proprietary) file formats. The version information is baked into most of the officially maintained software and I think there is nothing better than:


which tells you which version it is, that is has 8 additional commits, being g1e64b4c the last one and in this case even a Dirty flag because the evil user is not using the exact code from Git but changed it locally without making any commit :wink:

Btw. for these special cases, we have tools on the Python side and also on the Julia side (DrWatson.jl) which can even save the corresponding Git patch in the provenance information, so that it’s possible to restore the exact code even if the software repo was dirty.

Most of this stuff happens automatically, given that people use the base frameworks (we have like 4 of them in different languages and for different tiers) but so far it works fine.

I am just saying because having -dev tags or whatever in the version number requires some discipline and my experience over a decade in research (and maintaining research software) tells that people have no discipline, so you need to somehow bake it into package templates () and frameworks to make things reproducible and provenance trackable :wink:

Sorry, it was a bit off-topic.