go modules tldr

practical go modules


go modules tldr

practical go modules

go modules

Go modules are a collection of packages which share a single unit of versioning.

design goal: given the same set of initial dependencies always select the same set of all dependencies. (in contrast with SAT solvers which try to select the latest version of all dependencies)


check in go.mod and go.sum


Go modules depends on modules following semver as defined by semver.org.


v0 and v1 share the same namespace and allow seamless upgrading

version selection

example: the following modules / versions are available

1module-a v0.1.0 v0.2.0 v0.3.0 v1.0.0 v1.1.0-alpha.1
2module-b v1.4.0 v1.5.0 v1.6.0 v2.0.0 v2.1.0
3module-c v0.7.0 v0.8.0 v0.9.0
new dependency

if unspecified, select the latest released version with the current major version


indirect / existing dependency



By default the go toolchain will use a public proxy https://proxy.golang.org. This offers faster querying and download speeds.

multi module repositories


create a module

in go.mod:

1module example.com/module

the first part of the name SHOULD have a dot in the name, preferably domain like so go get can work, see vanity import paths. Only test/ and example/ are reserved to not need a dot.

go directive

in go.mod:

1go 1.X

Where 11 <= X <= current version. Lower versions guarantee the availability of features at that version, but restrict the availability of newer versions. Go does not automatically download older/newer toolchains, but the current one will report a mismatch if it fails to build.

require directive
replace directive

are only applied in the main module (the go build is being run from)

exclude directive


go.sum is not used for module selected / dependency resolution. It is purely for security / integrity. Do not worry about what's inside

dependency management

add a dependency

Add the dependency in your code with import "example.com/module", and run go run ., go build, go mod tidy to automatically update go.mod. The latest version will be selected and recorded (if not already there).

update a dependency
remove a dependency

Remove all imports in your code, run go mod tidy.


Vendoring is not necessary to guarantee the version of modules used, but you may want it to colocate your dependencies with your code, for auditing reasons, or for guaranteeing the availability of dependencies.

release new versions

patch versions

tag a new release

minor versions

tag a new release

major versions
v0 -> v1

tag a new release


update go.mod to new major version,

update all internal imports to use the new import path (unless you want to depend on an older version of yourself)

backwards compatibility

Sometimes you need to support legacy versions of go.

do nothing

update go.mod and imports as above, tag a new release.

release branch

cut a new branch for every release (major / minor / patch depends on how much granularity you want to support).

go1 branch

similar to the above approaches except the go1 branch has higher priority than the default branch

major subdirectory

Keep all existing code. Create a vX subdirectory where X == major version, ex v2. go mod init example.com/module/vX in the directory and copy all the other code in.

querying modules