Every real project depends on other modules, and the module system decides what code you actually build.
A module is a tree of packages versioned together, defined by go.mod at its root:
module example.com/shop
go 1.23
require github.com/google/uuid v1.6.0The module line is the import path prefix for your packages. The go line sets the minimum language version — and since Go 1.21, toolchains will download a newer Go if a module needs it (a toolchain line can pin one).
Day-to-day commands:
go get example.com/lib@v1.4.0adds or upgrades a dependency (@latestfor the newest release).go mod tidyadds missing requirements and removes unused ones. Run it before committing.go list -m allshows the full dependency graph;go mod why -m Xexplains why X is needed.
go.sum records cryptographic hashes of every module version used; commit it. Downloads go through the module proxy (proxy.golang.org) and are verified against the public checksum database.
Versions follow semantic versioning, and Go uses minimal version selection: it picks the lowest version satisfying every requirement, so builds are reproducible without a lock file. A breaking change (v2+) must change the import path to example.com/lib/v2, so v1 and v2 can coexist.
For local development across modules, go work init ./app ./lib creates a go.work workspace that builds them together; a replace directive in go.mod does the same for one module. Private repositories need GOPRIVATE=github.com/yourorg/* so the proxy and checksum database are skipped.
Example
// Typical workflow in a terminal:
//
// go mod init example.com/shop
// go get github.com/google/uuid@latest
// go mod tidy
//
// main.go
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
fmt.Println(uuid.NewString()) // e.g. 1b4e28ba-2fa1-11d2-883f-0016d3cca427
}Remember
- go.mod declares the module path, Go version and requirements
go mod tidykeeps requirements accurate; commit go.mod and go.sum- Major versions v2+ live at a different import path (
/v2)
Watch out for
- Forgetting to commit go.sum, or editing go.mod by hand instead of using go get / go mod tidy.