Skip to main content
eLearner.app
Module 9 · Lesson 4 of 544/50 in the course~12 min
Module lessons (4/5)

Go modules

A Go module is a versionable unit made up of one or more packages. It is the foundation of the modern dependency system (Go 1.11+): no more GOPATH, no more mandatory vendor, explicit and reproducible dependencies.

go.mod: the module manifest

Code
module example.com/myapp

go 1.22

require (
    github.com/google/uuid v1.6.0
    golang.org/x/time     v0.5.0
)

Three main directives:

  • module <path> — the module's import path. All internal packages are imported as example.com/myapp/sub/pkg. It does not have to be a real URL, but to publish via go get it must resolve.
  • go <version> — the minimum Go version required (also used to control which language features are allowed, e.g. range-over-func in 1.23).
  • require — the direct dependencies with their exact version.

Other directives: replace (substitutes a dep with a fork or a local path), exclude, retract.

go.sum: the cryptographic lockfile

Alongside go.mod, go.sum contains a cryptographic hash of EVERY downloaded version (including transitive dependencies). It guarantees reproducibility: if someone tampers with a published version, the build fails.

Always commit it. It is updated automatically by go commands.

Essential commands

Bash
go mod init example.com/myapp        # create go.mod
go get github.com/google/uuid        # add the dep at its latest version
go get github.com/google/uuid@v1.5.0 # specific version
go get -u ./...                      # upgrade every dep
go mod tidy                          # remove unused deps, add missing ones
go mod download                      # download everything into the cache
go mod why github.com/x/y            # explain why a dep is included
go mod graph                         # full dependency graph

go mod tidy is the one you run after every change to imports: it guarantees that go.mod reflects exactly the packages actually used.

Semantic Import Versioning (SIV)

Versions follow SemVer: v1.2.3 = MAJOR.MINOR.PATCH. The interesting part is major v2+:

  • Major v0 and v1 → normal path: github.com/foo/bar.
  • Major v2 or later → the path includes the major version: github.com/foo/bar/v2.
Go
import "github.com/foo/bar/v2"

This lets you import both v1 and v2 of the same library at the same time (useful during progressive migrations).

Import paths and internal packages

If your module is example.com/myapp, a utils/ sub-folder is imported as:

Go
import "example.com/myapp/utils"

The path depends only on the name declared in go.mod, not on the location on disk: the same code in a different folder keeps working.

Workspace mode (Go 1.18+)

To work on multiple modules that reference each other at the same time (e.g. a library and an app that uses it):

Bash
go work init ./lib ./app

This creates go.work: go build will use the local version of ./lib instead of downloading the published one. Do not commit go.work (it is a development environment).

Exercises

Exercise#go.m9.l4.e1
Attempts: 0Loading…

The module is example.com/myapp and contains a utils sub-folder. Import the sub-package in main using the full path.

Loading editor…
Show hint

The import path is the module name (from go.mod) plus the folder's relative path.

Solution available after 3 attempts

Exercise#go.m9.l4.e2
Attempts: 0Loading…

Turn the individual imports into an import group with the import ( ... ) syntax, importing both fmt and os.

Loading editor…

Solution available after 3 attempts

Quiz#go.m9.l4.e3
Ready

Which command removes dependencies no longer imported from go.mod and adds the missing ones?

Go
$ go mod ???
Answer options