

Released as part of Go 1.11 and now enabled by default in Go 1.16, Go Modules is the recommended way to manage dependencies, in this post I will cover the steps and commands needed for working with Go modules on a day-to-day basis.
According to the official documentation a Module
is (emphasis mine):
is a collection of Go packages stored in a file tree with a go.mod file at its root
This means a repository is not by definition a package but rather the folder with a go.mod
at its root; so in other words, a repository in practice could have multiple modules.
The content of the go.mod
file defines the following:
The Module name as well as the Go version are the only required parts of a go.mod
because in practice you can create a module that only uses the standard library.
For example a go.mod
could look like this:
module github.com/MarioCarrion/todo-api
go 1.16
require (
github.com/confluentinc/confluent-kafka-go v1.7.0
github.com/deepmap/oapi-codegen v1.5.1
github.com/elastic/go-elasticsearch/v7 v7.12.0
// ... more packages
)
To create a module we have to use the mod
tool in the form of:
go mod init <module name>
Under the root folder that is going to represent the final module, in the example above, I used the following to create it:
go mod init github.com/MarioCarrion/todo-api
Other than init, the tool mod
also defines other useful commands such as:
go.mod
file, meant to be used by CLIs and scripts,And a few more, you can use go help mod
to get more details about the other ones. I think the most used command after init is tidy because after adding a new module as a dependency you have to call it to clean up your go.mod
.
The other tools in the Go toolchain are module-aware, so for example get
, build
or test
when detecting new dependencies added, they invoke behind the scenes the required mod tools to download the needed packages and update go.mod
.
Adding a new dependency, for example github.com/gorilla/mux
, can be done a few different ways:
go mod download
and go mod tidy
.Or
go get github.com/gorilla/mux
,go mod download
and go mod tidy
.The difference in steps is whether we want to explicitly get a concrete version or not, so assuming we want to get version v1.8.0
we should be using go get github.com/gorilla/mux@v1.8.0
in the first step of the second workflow.
This versioning mechanism brings another important thing to know: Semantic Versioning, I covered SemVer when I talked about Versioning REST APIs, the idea is exactly the same, module authors are expected to follow those guidelines when publishing their modules.
Upgrading a module follows a similar workflow by using get
, for example to upgrade the module we use:
go get -u github.com/gorilla/mux
That will update the module to the most recent version, if we are only trying to see if there are updates available then using something like this tells us:
$ go list -m -u github.com/elastic/go-elasticsearch/v7
github.com/elastic/go-elasticsearch/v7 v7.12.0 [v7.13.0]
The output above indicates there’s a new release for the Elasticsearch package.
Downgrading a module follows a similar step we did when indicating a version but this time we use a version lower to the one we currently have, for example:
go get github.com/gorilla/mux@v1.7.4
Like I mentioned before SemVer is a fundamental part of versioning in Go, understanding and following those guidelines is a must when creating Go Modules; those versions in the end are indicated as tags in the versioning control system.
For example to publish a version v1.2.3
in a module that happens to use Git, we should create a tag using something like:
git tag v1.2.3
git push origin --tags
In cases where we have the need to create a major version, for example from v1.x.x.
to v2.x.x
; there are two strategies to follow:
When using Branches the idea is to literally create a new branch, for example in Git:
git checkout -b v2
A real example of this approach is the github.com/olivere/elastic
package for Elasticsearch.
When using Folders the idea is to create a folder with the major version name, for example v2
that is going to include a new go.mod
. A real life example of this the googleapis/gax-go/v2
package.
For both cases we must modify the go.mod
file to indicate that v2
version in the module name, for example:
module github.com/MarioCarrion/todo-api/v2
go 1.16
// ... everything else
If you’re looking to expand more about Go Modules, I recommend reading the following links: