Go.mod
External
Internal
Overview
go.mod
declares the module path, which is the import path prefix for all packages within the module. It also tracks the modules that provide dependencies to this module. go.mod
is located in the root of the module, which is also the root of the source tree for the module. The most common way to create a go.mod
is with go mod init <module-path>
. The file can also be created manually with a text editor, and then edited with the same text editor, but Go documentation recommends to make changes to the file via go
commands.
go.mod
stays with the code, including in the source repository.
A typical go.mod
file usually assumes that your project is hosted in GitHub, but this is not a requirement. The module path can be anything.
As go
tools are used to manage dependencies, the tools update the go.mod
file so that it maintains the current list of dependencies.
go.sum
When a dependency is added, go
creates a go.sum
file that contains checksums, in form of cryptographic hashes, of dependency modules. This is used to verify the integrity of the downloaded module files. This file should not edited manually.
go.mod Example
module example.com/hello
go 1.21.0
require rsc.io/quote v1.5.2
require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/sampler v1.3.0 // indirect
)
Initialize go.mod
In the module root directory, initialize the go.mod
file.
go mod init <module-path>
go mod init example.com/generic
go.mod Editing Commands
Do not modify go.mod
manually, always use go mod
editing commands to ensure that requirements described by the file remain consistent.
edit
-require
go mod edit -require=...
Examples below.
-droprequire
go mod edit -droprequire=github.com/apache/yunikorn-scheduler-interface
-replace
go mod edit -replace=...
Examples below.
Go Version
module example.com/hello
go 1.22.4
Adding a Dependency to a Module
Dependencies are added with the go get
command. The command updates go.mod
by adding the require
directive for dependencies. The require
directive tracks the minimum version of a module that the module depends on. The command also updates the module source code and places in the module cache and authenticate each module it downloads. This ensures that it's unchanged from when the module was published.
go get [-u] github.com/apache/yunikorn-core@v1.4.0
For a post v1 module, postfix /vx
to the module path:
go get github.com/labstack/echo/v4@v4.11.4
Note that you are adding the dependency in advance without actually referring it from the module source code, go get
will add an "// indirect" comment for that specific dependency in go.mod
.
If the exact latest version is unknown, use the following syntax to let go get
determine it:
go get google.golang.org/protobuf/reflect/protoreflect
TODO: https://pkg.go.dev/cmd/go#hdr-Add_dependencies_to_current_module_and_install_them
Variations of go get
Removing a Dependency from a Module
See go mod edit -droprequire
above.
Update Module's Dependencies
Use go list
to check if there are newer versions of dependencies. If there are available useful upgrades, use go get
command again to add the particular newer version.
Synchronize Dependencies
TODO: https://go.dev/doc/modules/managing-dependencies#synchronizing
Using Unpublished Module Code
Normally, go get
is used with published, versioned releases of a project's dependencies. However, there are situations that require experimentally modifying a dependency to use it with the current project. The Go documentation refers to this situation as "developing and testing against unpublished module code". There are two ways to access a modified dependency: in a local directory on the development machine and in a forked repository.
Using Local Module Code
A very common situation when experimenting with the source of a dependency is to clone the dependency repository locally, and modify the code. It is convenient, and possible, to express the go.mod
dependency to point to the local directory. The go.mod
syntax to express this situation is:
...
require example.com/somemodule v0.0.0-unpublished
replace example.com/somemodule v0.0.0-unpublished => ../somemodule
The configuration expresses the fact the dependency version we intend do use is not published anywhere (v0.0.0-unpublished
), and the tool chain must reach out to the local directory ../somemodule
to get it. The replace
directive specifies the location. An absolute path can be used, but that might introduce problems if go.mod
is shared within a team, and the path is not consistent across developers' machines.
Avoid modifying go.mod
manually. Use the following command to generate the configuration:
go mod edit -require=example.com/somemodule@v0.0.0-unpublished
# Careful when using copy-and-paste, the first command uses "-require", the second "-replace"
go mod edit -replace=example.com/somemodule@v0.0.0-unpublished=../somemodule
Example:
go mod edit -require=github.com/apache/yunikorn-core@v0.0.0-unpublished
go mod edit -replace=github.com/apache/yunikorn-core@v0.0.0-unpublished=/Users/ovidiu/projects/yunikorn/github-ovidiuf-forks/yunikorn-core
Use go get
to pull the source code in the module cache:
go get example.com/somemodule@v0.0.0-unpublished
Using an Arbitrary Fork Module Code
The same pattern as in Using Local Module Code applies, but this time the replace
statement refers to an actual repository.
The go.mod
should look like:
...
require github.com/apache/yunikorn-core v0.0.0-unpublished
replace github.com/apache/yunikorn-core v0.0.0-unpublished => example.com/myfork/yunikorn-core v1.2.3-fixed
The edit commands are:
go mod edit -require=github.com/apache/yunikorn-core@v0.0.0-unpublished
go mod edit -replace=github.com/apache/yunikorn-core@v0.0.0-unpublished=example.com/myfork/yunikorn-core@v1.2.3-fixed
Instead of a specific version, a commit hash or a branch name can be used instead, as show below in the Getting a Specific Commit section.
Getting a Specific Commit
To get a specific commit, use the commit hash or a branch name:
go get example.com/theirmodule@4cf76c2
go get example.com/theirmodule@of/some-branch
This command will modify go.mod
as follows:
require example.com/theirmodule v0.0.0-20240109203350-28b9035e2013
If the dependency on a dot version is already declared in the go.mod
:
require official.com/somemodule v1.0.0
and we want to (temporarily) replace it with the dependency defined by a specific commit or branch name in a different repository, use go mod edit -replace
as follows:
go mod edit -replace=official.com/somemodule@v1.0.0=experimental.com/somemodule@4cf76c2
go mod edit -replace=official.com/somemodule@v1.0.0=experimental.com/somemodule@of/somebranch
This command will modify go.mod
as follows:
replace official.com/somemodule v1.0.0 => experimental.com/somemodule v0.0.0-20240109203350-28b9035e2013
The version label eventually stored in the go.mod
file has a timestamp "...-20240117154324-..." and a commit hash "...-4323f643fa79", that contains the first 12 most significant digits of the GitHub commit.