go.mod and go.sum Explained

What a Go module is, what each line in go.mod means, what go.sum is for, and why you no longer need GOPATH.

A module is a collection of Go packages that are versioned and released together. The go.mod file at its root names the module and lists what it depends on. Since Go 1.16, modules are the default way to build Go code, and the old GOPATH workspace is no longer needed for your own projects.

Creating a Module

mkdir shop && cd shop
go mod init example.com/shop

The output is:

go: creating new go.mod: module example.com/shop

and the new go.mod contains:

module example.com/shop

go 1.24.4

The module path example.com/shop is the prefix of every import path in this module. If you plan to publish the code, use the repository location, for example github.com/yourname/shop, so go get can find it. For code that is never published, any name works, though a domain-like name avoids clashes with standard library paths.

You do not need GOPATH anymore:

Before modules, all Go code had to live inside $GOPATH/src. With modules, a project can be anywhere on disk. GOPATH still exists, mainly as the place where downloaded modules are cached ($GOPATH/pkg/mod) and where go install puts binaries ($GOPATH/bin), but you do not need to set it or put code under it.

The Lines in go.mod

A go.mod for a project with dependencies looks like this:

module example.com/shop

go 1.24

toolchain go1.24.4

require (
	github.com/google/uuid v1.6.0
	golang.org/x/sync v0.10.0
)

require golang.org/x/text v0.21.0 // indirect

replace example.com/shop/legacy => ../legacy
  • module names this module.
  • go sets the minimum Go version for this module. It also controls language behavior, such as the per-iteration loop variables added in Go 1.22.
  • toolchain (optional) suggests a specific Go release to use.
  • require lists dependencies and their minimum versions.
  • // indirect marks a module your code does not import directly but one of your dependencies needs.
  • replace swaps a module for another location, such as a local folder.

You rarely edit go.mod by hand. Commands like go get and go mod tidy keep it up to date.

What go.sum Is For

go.sum stores a cryptographic checksum for every module version your build uses:

github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=

When Go downloads a module, it checks the files against these hashes. If anything differs, for example because someone changed a published tag, the build stops with a SECURITY ERROR message instead of using unexpected code. New hashes are also checked against the public checksum database at sum.golang.org.

Commit both go.mod and go.sum to version control.

Missing go.sum entries:

Errors like missing go.sum entry for module providing package github.com/google/uuid mean go.sum is out of date, often after editing go.mod by hand or a merge conflict. Run go mod tidy to fix it.

Where Downloaded Modules Live

Downloaded modules are stored read-only in the module cache, usually $HOME/go/pkg/mod. Every project on your machine shares it, so each version is downloaded once. go clean -modcache deletes the cache if it ever gets into a bad state; modules are downloaded again on the next build.

Running go commands outside a module:

Running go build in a folder with no go.mod above it fails with go: go.mod file not found in current directory or any parent directory; see 'go help modules'. Run go mod init first, or cd into the project.

Your module is set up correctly:

go.mod and go.sum are committed, go build ./... works from a fresh clone anywhere on disk, and go mod tidy produces no changes.

Summary

A module is a versioned set of packages defined by go.mod, created with go mod init. go.mod holds the module path, minimum Go version, dependencies and replacements, while go.sum stores checksums that protect against changed downloads. Commit both, let the go command maintain them, and keep projects anywhere on disk, since GOPATH is no longer where your code needs to live.