Using Go Modules
Go Modules is the official dependency management solution for the Go programming language. Recently, I finally converted over my personal projects. I had been putting it off for some time, since I was waiting for the Go team to finalize everything and work out all the kinks. Go 1.11 was when Modules was first released as a beta. Go 1.12 still had Modules in beta mode and Go 1.13 was when Modules came out of beta. After Go 1.14 came out, I figured it was probably time to transition over from dep (which is deprecated now). It was a mostly smooth experience, but I did run into some snags. For example, upgrading a package that has already had its major version incremented to 2 or greater requires a bit more work. In an effort to share my findings, here are some common commands I found useful.
Initialize a new module
This command is only used once to create a new module or to convert an existing package. It creates a new go.mod
file. If the package was previously using some other form of Go dependency management, it should automatically determine dependencies based on the previous tool. For example, my projects used dep and Modules locked dependencies based on dep’s Gopkg.toml
.
go mod init
Tidy up dependencies
This is the go-to command that should be run any time changes are made to a project. This command will add missing dependencies or remove extraneous dependencies. It ensures the go.mod
file matches the dependencies a package is actually using.
go mod tidy
Vendor all dependencies
The general consensus among the Go community is that vendoring is no longer needed and we can rely on the Go module proxy to store dependency versions. For those that still desire to vendor their dependencies, modules provides the capability to copy all modules referenced in your project to the vendor folder using the following command:
go mod vendor
Update dependencies
Updating dependencies is integrated with the go get
command in the standard Go toolchain. This command will update a singular dependency:
go get -u github.com/eleniums/async
Update a dependency to a specific version:
go get github.com/eleniums/async@v2.2.0
This command will update ALL dependencies in your package:
go get -u ./...
Determine how a dependency is referenced
Figure out how a dependency is used:
go mod why -m github.com/eleniums/async
Another method for determining how a dependency is used:
go mod graph | grep github.com/eleniums/async
This command will list all direct dependencies of a module:
go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all
Delete modules cache
You shouldn’t typically need to clear the module cache, but in the event something goes horribly wrong and Modules is unable to recover, it’s useful to know how to clear the cache and start fresh.
go clean -modcache
Convert an existing package to Modules
I found it was really easy to convert an existing v1 package to Modules. The process was simple:
- Run
go mod init
- Remove old dependency management files (Gopkg.toml and Gopkg.lock for dep)
- Increment the minor version (recommended)
But what to do if a package is already on v2 or beyond? One of the design philosophies behind Go is backwards compatibility. Modules was designed with this in mind and can actually support multiple major versions of the same module side by side. Unfortunately, it basically expects you to still be on v1 when you convert to Modules. If you are on major version 2 or greater, Modules expects v2 (or v3, etc.) to be part of the package path. There are some ways around this, but I found them to not be desirable and it was easier to just bite the bullet and create a full major version upgrade. The general steps for a major version Modules conversion:
- Run
go mod init
- Remove old dependency management files (Gopkg.toml and Gopkg.lock for dep)
- Increment the minor version (recommended)
- Copy code files to new v2 folder
- Copy
go.mod
andgo.sum
files to v2 folder - Adjust module path in
v2/go.mod
to include /v2 at the end
For an example of a converted package with a major version of 2 or greater, take a look at one of the following projects:
References
Here are some links that I found useful when learning about Go Modules: