Major Versions in Go Modules Explained

Elliot Chance
Mar 29 · 3 min read

Go Modules is still a relatively new feature and some of the documentation surrounding it is detailed and technical, but not easily digestible as a quick start.

One issue I ran into is dealing with packages that have a version of 2.x.x or higher. It’s not immediately obvious but Go modules handles packages that have a major version that is not v0.x.x or v1.x.x in a special way.

I won’t go into why this is so. The bottom line is that if you publish a package with a version of v2.0.0+ or publish a new major version there are some extra steps in your package and the packages that depend on it.


In this example I will be publishing v7.0.0 of github.com/kounta/luigi (one of our private repositories, but you can substitute the name with your own). It already uses go modules, but it has never had its major version taken into special consideration. This causes packages that depend on it to force a specific version in their go.mod:

github.com/kounta/luigi v0.0.0–20190328234950-d6354a0da43d

We would rather have the tagged version, like:

github.com/kounta/luigi v7.0.1

The odd thing is that if I change the version manually (in go.mod), Go will just revert it back to the specific hash and checksum. What’s going on!?

Before we start there is an important consideration here. If you want to support multiple major versions or not. In my case we only want to support the current major version since it is an internal library. Any projects that depend on it will eventually need to update their dependencies which will trigger them to update luigi to the latest version.

However, if you need to support multiple major versions at the same time I will explain this separately later in Maintaining Multiple Major Versions.

Updating the Package

module github.com/kounta/luigi/v7

This may seem obscure at right now. The next step will show why this is needed.

Run go build(or go test if you have tests) and you will receive errors like:

./log_entry_test.go:14:14: undefined: luigi.NewLogEntry
./log_http_test.go:15:78: undefined: luigi.Environment

This is because we have changed the name of the current package. Technically Go is giving these errors because there is no longer a luigi@v0.x.x or luigi@v1.0.0 available.

We will need to update our imports to the new package name (including test files):

import “github.com/kounta/luigi/v7”

My first through was, “Oh, no! Will I have to reference v7.xinstead of luigi.xeverywhere?” Actually, no. Only the import name changes, and Go understands we are talking about the version on the end. Phew.

It could be painful if you have many imports to update. A global search and replace might be necessary.

Once go build/test passes you should run go mod tidy, not only because it’s a good idea but also because it will remove any references to the old version of this package that might have been added from a go build/test while refactoring.

Now commit all changes including the go.mod and go.sum.

Updating The Packages That Depend On Luigi

There are two ways to do this:

  1. Simply run (notice the version is now in the package name): go get github.com/kounta/luigi/v7@v7.0.1
  2. Or, edit the go.mod manually and change the version and package name, from: github.com/kounta/luigi v0.0.0–20190328234950-d6354a0da43d to: github.com/kounta/luigi/v7 v7.0.1

When you run go build/test you will get the same kind of error as before. It requires the same fix. That is, changing the import names to include the version number on the end.

Finally, run go mod tidy for good measure. You are done!

Maintaining Multiple Major Versions

Let’s say I had to manage both v6 and v7 (the latest) of luigi. Before embarking on the changes above you should copy the go.mod and go.sum into a folder called v6:

mkdir v6
cp go.mod go.sum v6

Any consumers that wish to remain on v6can with the import:

import “github.com/kounta/luigi/v6”

Go will automatically resolve this to the versioned folder in the repository. Easy. It’s also a nice way to indicate how many major versions back your package officially supports.


Originally published at http://elliot.land on March 29, 2019.

Elliot Chance

Written by

I’m a data nerd and TDD enthusiast from Sydney. I love exploring new technologies and working on modern ways to solve age old problems 🤓 elliotchance@gmail.com