A Complete Guide to Go Modules
Introduction
Working with modules is a crucial aspect of any programming language, including Go. Go has built-in support for managing modules and dependencies and since the introduction of Go modules in Go 1.11, they have become the standard way of handling dependencies in Go.
Go modules offer several advantages over older dependency management techniques, such as GOPATH and Vendoring. Unlike Vendoring, Go modules provide a simple and straightforward method for declaring, managing, and updating dependencies without the need for committing them to source control. Unlike GOPATH, which manages dependencies globally, Go modules enable project-level dependency management, making it easier to handle multiple projects with varying dependencies.
Why Go modules?
Go modules provide a centralized repository for managing project dependencies, enabling easier sharing of code and collaboration with others. They also offer versioning and Semantic Import Versioning (SIV), which helps to prevent breaking changes in dependencies.
Package vs Module
Before we dive into the details of Go modules, we must understand the distinction between a package and a module. A package is a collection of Go source files in the same directory that define functions, types, and variables, declared using the package keyword. A module, on the other hand, is a collection of related Go packages that are versioned as a single unit. A module can contain one or more packages and the go.mod
file is used to declare the module.
In this article, we will cover the basics of Go modules and how to use them in your projects.
Prerequisites
This article assumes that you have Go version 1.14 or higher installed on your machine. If you don’t have Go installed on your machine, you can download it from here
Setting up and using Go modules
Initializing a module
Create a new directory and navigate to it.
To initialize a new module, run the go mod init
command. This command will create a new go.mod
file in the current directory. You have to specify the name of the module as an argument to the go mod init
command. The name of the module should be the name of the module as it will appear in the import statements.
If you open the go.mod
file, you will see the following content.
The module
directive specifies the name of the module. The go
directive specifies the version of the Go language used to build the module. go.mod
file does not track built-in packages such as fmt
or net/http
. It only tracks the third-party packages that you import into your project.
For instance:
If you cat
the go.mod
file, you will see that it is still empty.
Adding dependencies
To add a dependency to your project, you have to import it into your code. For instance, let’s import the github.com/labstack/echo/v4
package in our code.
So as for your program to run you must first install the github.com/labstack/echo/v4
package. To do that, run the go get
command.
If you cat
the go.mod
file, you will see that it has been updated with the github.com/labstack/echo/v4
package.
From running this command, Go will download the echo
package and all of its dependencies and add them to the go.mod
file. In the go.mod
file, you can see two sections, first require
and the second require
with the // indirect
comment. The first require
section contains the direct dependencies of the module. The second require
section contains the indirect dependencies of the module. Indirect dependencies are the dependencies of the direct dependencies.
go.sum file
If you check your directory, you will see that a new file go.sum
has been created. This file is the checksum database for the Go module. It records the expected cryptographic checksums of the content of specific module versions, including both direct and indirect dependencies.
The purpose of the go.sum
file is to ensure that the content of the module is the same as the content of the module when it was first downloaded. This is important because the content of the module can change over time. When a Go module is built or tested, Go will compare the cryptographic checksums of the module’s content with the cryptographic checksums recorded in the go.sum
file. If the cryptographic checksums do not match, it means that the packages have been tampered with, and Go will prevent the build or test from running. go.sum
behaves like a lock file in other languages.
Go Mod Commands
We have seen a few commands that we can use to work with Go modules. In this section, we will cover the rest of the commands that we can use to work with Go modules.
go mod tidy
The go mod tidy
command is used to update the go.mod
file and the go.sum
file. It adds any missing dependencies and removes any unused dependencies. It is a best practice to run this command after adding or removing a dependency.
It also updates the versions of dependencies that are already in the go.mod file to the latest version that is compatible with the current code.
go mod vendor
The go mod vendor
command is used to copy all the dependencies of the module into a subdirectory named vendor
in your project directory. This allows you to build and run your projects without internet access.
go mod download
The go mod download
command is used to download the dependencies of the module into the module cache. The downloaded dependencies are stored in the ~/go/pkg/mod
directory.
The go mod download
command is typically used as part of the go build process. When you run the go build
command, Go will first run the go mod download
command to download the dependencies that are not already in the module cache.
Running the go mod download
beforehand can ensure that the dependencies are already available, and prevent builds from failing due to network issues.
go mod verify
The go mod verify
command verifies the dependencies of the module. It checks that the cryptographic checksums (hashes) of the downloaded dependencies match the cryptographic checksums recorded in the go.sum
file. It ensures the integrity and authenticity of the downloaded dependencies.
If the hashes match the go mod verify
command will output all modules verified
. If the hashes do not match, the go mod verify
will output an error indicating that the verification has failed. In this case, the packages should not be used and should be re-downloaded.
go mod graph
The go mod graph
command is used to print the module requirement graph in the format module@version requirement@version
. It is useful for debugging and understanding the dependencies of the module.
Each module is identified by its module path and version and the output includes information on the required and direct dependencies of each module, including indirect dependencies.
go mod why
The go mod why
command is used to print why a specific module is included as a dependency. This information is important in understanding why a specific module is a dependency and what part of the code is using it.
The -m
flag is used to specify the module that we want to know why it is a dependency. The output will include the module path.
Conclusion
In this tutorial, we have learned how to use Go modules as a dependency management tool. We have seen how to create a new module, add dependencies, and how to work with the go.mod
and go.sum
files. We have also seen a few commands that we can use to work with Go modules.
That’s it for this tutorial. I hope you found this tutorial useful.