Module Basics
go.mod ยท module path ยท go version A module is a collection of packages with a shared module path.
Every module has a go.mod file at its root.
myproject/
โโโ go.mod โ defines module path and Go version
โโโ go.sum โ cryptographic hashes of all dependencies
โโโ main.go
โโโ internal/
โโโ config/
โโโ config.go โ package path: github.com/you/myproject/internal/config
go.mod โ anatomy
go.mod
// go.mod module github.com/you/myproject go 1.22 require ( github.com/gin-gonic/gin v1.9.1 golang.org/x/sync v0.7.0 ) require ( // indirect dependencies โ pulled in transitively github.com/bytedance/sonic v1.11.3 // indirect )
Create a new module
go mod init
# Create go.mod in current directory go mod init github.com/you/myproject # Tidy: add missing, remove unused dependencies go mod tidy # Download all dependencies to module cache go mod download # Vendor all dependencies into ./vendor/ go mod vendor # Print module graph go mod graph
go.sum โ content hashing
go.sum
# go.sum records SHA-256 hashes for every # dependency version used, plus its go.mod. # It is machine-generated โ do not edit by hand. # Commit it to source control. # Verify all modules against go.sum go mod verify # If go.sum is out of date after editing go.mod: go mod tidy
Managing Dependencies
go get ยท go install ยท upgrade
go get โ add and upgrade dependencies
go get
# Add a dependency (latest version) go get github.com/pkg/errors # Add a specific version go get github.com/pkg/errors@v0.9.1 # Upgrade to latest patch release go get github.com/pkg/errors@patch # Upgrade to latest minor release go get github.com/pkg/errors@latest # Upgrade all dependencies to latest minor/patch go get -u ./... # Remove a dependency (then go mod tidy to clean up) go get github.com/pkg/errors@none
go install โ install CLI tools
go install
# Install a tool to $GOPATH/bin go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest # Install a specific version go install golang.org/x/tools/cmd/goimports@v0.20.0 # go install vs go get: # go install โ for tools you run from the CLI # go get โ for library dependencies in a module
Listing dependencies
go list
# List all direct and indirect dependencies go list -m all # List with JSON output go list -m -json all # Show why a package is needed go mod why github.com/pkg/errors # List outdated dependencies go list -m -u all
Versioning
semver ยท major versions ยท MVSGo modules use Minimum Version Selection (MVS): the build uses the minimum version of each dependency that satisfies all requirements. This makes builds reproducible without a lock file mechanism separate from go.mod.
Semantic versioning: v MAJOR . MINOR . PATCH
โ โ โโโ Bug fixes, no API change
โ โโโโโโโโโโโ New features, backwards compatible
โโโโโโโโโโโโโโโโโโโ Breaking API changes
Go rule: v2+ modules must change their import path:
v1: github.com/you/pkg
v2: github.com/you/pkg/v2 โ new import path
v3: github.com/you/pkg/v3
Importing a v2+ module
Major versions
// go.mod require github.com/foo/bar/v2 v2.3.0 // source code โ import path includes /v2 import "github.com/foo/bar/v2" // v1 and v2 can coexist in the same build import ( barv1 "github.com/foo/bar" barv2 "github.com/foo/bar/v2" )
Pre-release & pseudo-versions
Versions
# Pre-release tag go get github.com/foo/bar@v1.0.0-beta.1 # Pseudo-version: commit hash before first tag # v0.0.0-20240115123456-abcdefabcdef # Generated automatically when pointing to a commit: go get github.com/foo/bar@main # Point to a specific commit go get github.com/foo/bar@abc1234
replace Directives
local path ยท fork ยท retract
replace โ local development and forks
replace
// go.mod โ replace a dependency with a local path replace github.com/you/shared => ../shared // Replace with a fork (pinned to a specific version) replace github.com/original/pkg => github.com/yourfork/pkg v1.2.3 // Replace with a fork at a commit replace github.com/original/pkg => github.com/yourfork/pkg v0.0.0-20240101000000-abc123
replace directives only apply to the module that declares them โ they do not propagate to users of your module. Do not publish a library with local-path replace directives; remove them before tagging a release.
retract โ un-publish a bad version
retract
// go.mod โ retract a version you released by mistake retract v1.3.0 // critical bug introduced // Retract a range retract [v1.3.0, v1.3.2] // go get will warn about retracted versions // Existing users are not auto-upgraded
exclude โ ban a specific version
exclude
// go.mod โ prevent a known-bad version from being selected exclude github.com/foo/bar v1.2.3 // MVS will skip to the next available version // Useful if a dependency published a broken release // and you can't wait for them to retract it
Workspace Mode
go.work ยท multi-module ยท go workGo workspaces (Go 1.18+) let you work on multiple modules simultaneously without editing go.mod replace directives. A
go.work file at the repo root overrides dependency resolution for the listed modules. myrepo/
โโโ go.work โ workspace file; not committed to library repos
โโโ service/
โ โโโ go.mod (module github.com/you/service)
โ โโโ main.go
โโโ shared/
โโโ go.mod (module github.com/you/shared)
โโโ util.go
service/ imports github.com/you/shared โ resolved from ../shared/ locally
go work commands
go work
# Create go.work and add current module go work init ./service ./shared # Add another module to an existing workspace go work use ./newmodule # Sync workspace โ update go.work.sum go work sync # Disable workspace for a single command GOWORK=off go test ./...
go.work file anatomy
go.work
go 1.22 use ( ./service ./shared ) // Optional: replace directives here override // all modules in the workspace replace github.com/external/dep => ../local-dep
Packages
naming ยท internal ยท init ยท blank import
Package rules and naming
package
// Package name is the last element of its import path // import "github.com/you/proj/config" โ package config // All files in a directory share one package name // Exception: _test.go files may use package foo_test // Package names: short, lowercase, no underscores // Good: config, httputil, timeutil // Bad: myConfig, http_util, util (too generic) // Exported identifiers start with a capital letter func DoWork() {} // exported func doWork() {} // unexported
internal โ restrict visibility
internal
// Packages under internal/ can only be imported by // code rooted at the parent of the internal/ directory myproject/ โโโ internal/ โ โโโ auth/ // importable by myproject/... โ โโโ auth.go โโโ api/ โโโ api.go // can import internal/auth // External packages cannot import internal/auth // The compiler enforces this โ no runtime check
init functions & blank imports
init ยท _
// init() runs automatically after package-level vars are initialized // A package can have multiple init() functions, even in different files func init() { log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) } // Blank import: import solely for init() side effects // (e.g., registering a database driver) import _ "github.com/lib/pq" // registers postgres driver import _ "github.com/mattn/go-sqlite3" // registers sqlite3 driver import _ "image/png" // registers PNG decoder // init() order: dependencies first, then importing package // Within a package: source file order (alphabetical by filename)
Private Modules
GONOSUMCHECK ยท GONOSUMDB ยท GOFLAGS
GONOSUMDB / GONOSUMCHECK
GONOSUMDB
# Tell Go not to use the checksum database for private modules GONOSUMDB=github.com/yourorg/* # Or set permanently in go env go env -w GONOSUMDB=github.com/yourorg/* # Skip sum verification entirely for a pattern go env -w GONOSUMCHECK=github.com/yourorg/* # Multiple patterns (comma-separated) go env -w GONOSUMDB=github.com/yourorg/*,gitlab.yourcompany.com/*
GOPRIVATE & GOPROXY
GOPRIVATE
# GOPRIVATE sets both GONOSUMDB and GONOPROXY go env -w GOPRIVATE=github.com/yourorg/* # Use a private proxy, fall back to direct go env -w GOPROXY=https://proxy.company.com,direct # Bypass proxy for private modules go env -w GONOPROXY=github.com/yourorg/* # Direct fetch only (no proxy) GOPROXY=direct go get github.com/yourorg/secret
The simplest setup for a private org on GitHub:
go env -w GOPRIVATE=github.com/yourorg/*. This skips both the proxy and the checksum database for all modules under that org. Make sure your SSH or HTTPS credentials are configured for git.Quick Reference
Cheat-sheet| Command / Concept | Syntax | Notes |
|---|---|---|
| Init module | go mod init github.com/you/proj | Creates go.mod |
| Tidy | go mod tidy | Add missing, remove unused |
| Download | go mod download | Fill module cache |
| Vendor | go mod vendor | Copy deps to ./vendor |
| Verify | go mod verify | Check hashes against go.sum |
| Add dependency | go get github.com/pkg/foo | Latest version |
| Pin version | go get github.com/pkg/foo@v1.2.3 | Exact version |
| Upgrade all | go get -u ./... | Latest minor/patch |
| Remove dependency | go get github.com/pkg/foo@none | Then go mod tidy |
| Install tool | go install tool/cmd@latest | Installs to $GOPATH/bin |
| List modules | go list -m all | All direct + indirect |
| Why needed | go mod why github.com/pkg/foo | Explains dependency chain |
| Replace (local) | replace mod => ../localdir | in go.mod; don't publish |
| Replace (fork) | replace orig => fork@v1.2.3 | in go.mod |
| Retract version | retract v1.3.0 | Warn users; don't auto-upgrade |
| Init workspace | go work init ./mod1 ./mod2 | Creates go.work |
| Add to workspace | go work use ./mod3 | Appends to go.work |
| Sync workspace | go work sync | Updates go.work.sum |
| Disable workspace | GOWORK=off go build | One-off; ignores go.work |
| internal/ package | package internal/auth | Only parent tree can import |
| Blank import | import _ "pkg" | Runs init() only; registers drivers |
| v2 import path | github.com/you/pkg/v2 | Required for breaking changes |
| Private modules | go env -w GOPRIVATE=org/* | Skips proxy and sum DB |