Setting up Go: modules, toolchain and editors

Installing Go, go mod init, go.mod and go.sum, module versus workspace mode, gofmt, go vet, and editor integration that actually helps.

Install and inspect the toolchain

Go installs as one toolchain: the go command is the compiler, the build system, the test runner and the module manager. There is no separate package manager to learn, and no build file to write before the first program runs.

go version                     # go1.24.1 darwin/arm64
go env GOROOT GOPATH GOMODCACHE GOTOOLCHAIN

# persist a default for every future shell
go env -w GOPROXY=https://proxy.golang.org,direct
go env -w GOFLAGS=-mod=mod
VariableWhat it controls
GOROOTWhere the toolchain and standard library are installed; set by the installer, rarely changed by hand
GOPATHYour workspace for go install binaries and legacy layout; defaults to ~/go
GOMODCACHEWhere downloaded module versions are unpacked and cached
GOTOOLCHAINWhether go may download a newer toolchain than the one installed
GOPROXYWhere modules are fetched from; off forces the module cache only
CGO_ENABLED0 disables cgo, which is what you want for portable static binaries

go env -w writes to a per-user environment file, so the setting survives new shells without editing shell profiles. go env -u removes it.

Modules: go.mod and go.sum

mkdir notes && cd notes
go mod init example.com/notes      # creates go.mod; the path is the import prefix
go get github.com/google/uuid      # adds a require line and updates go.sum
go mod tidy                        # add what is used, remove what is not
go mod graph                       # who depends on what
go mod vendor                      # copy dependencies into vendor/
module example.com/notes

go 1.24                // the language version this module is written for
toolchain go1.24.1     // preferred toolchain when building

require (
    github.com/google/uuid v1.6.0
)

exclude github.com/old/broken v1.2.3

replace example.com/legacy => ../legacy   // local override while developing
  • The module path is both the identity of the module and the prefix of every package inside it. Choose a path you could actually publish, even for private code.
  • go.mod records your requirements. go.sum records cryptographic hashes of exact versions and is what makes builds reproducible; commit both.
  • A go.sum mismatch is a security event, not a nuisance. Do not delete the file to make an error go away.
  • Workspace mode (go work init ./api ./lib) creates a go.work file that links several modules from one checkout, which is the modern way to develop two modules together.
  • go mod tidy should be run before every commit that touched imports; CI should fail when it changes anything.

The daily workflow

gofmt -l .            # list files that are not formatted
gofmt -w .            # rewrite them
go vet ./...          # suspicious constructs the compiler accepts
go build ./...
go run ./cmd/notes    # build and execute in one step
go test ./...
go test -race ./...
go install ./cmd/notes   # builds into GOPATH/bin
  • Run gofmt on save, not as a review comment. Formatting is not a style debate in Go; it is one command.
  • go vet catches real bugs such as a mis-typed format verb or a lock copied by value. Its findings should be treated as errors.
  • Editor support comes from gopls, the language server: install it once with go install golang.org/x/tools/gopls@latest and configure format-on-save plus organize-imports.
  • Module mode is the default and GO111MODULE is no longer needed. If a build behaves oddly, check whether a stale go.work file in a parent directory is in scope.
💡
A new project needs exactly three things: go mod init, a main.go, and format-on-save. Everything else — Dockerfiles, linters, CI — can wait until the code does something. Setup ceremony is the most common way beginners lose an evening.

FAQ

Do I commit go.sum?
Yes, for applications and libraries alike. It pins hashes of the exact dependency versions, so every machine and CI runner builds the same code. Only a library with no dependencies has nothing in it.
What is the difference between go get and go mod tidy?
go get adds or upgrades a specific module and changes versions intentionally. go mod tidy reconciles go.mod with what the source actually imports, and is what you run routinely.

Packages, project layout and dependencies The standard library toolkit

Last refreshed 2026-09-18.