skip to content

Modules, Build and Toolchain

Everything around the code: the module graph that fixes which versions build, the one go command that compiles, formats and checks them, the artifact you ship, and the Go version your module speaks.

part ofGo (Golang)overview, primer and where to startread it →
on this pageshow

explore

questions

114 · 5 sections

What does a `replace` directive in go.mod do, and how do you point one at a local directory?

level: juniorimportance: must knowfreq 60%
basics
~20 s

A replace directive in go.mod redirects a module path to something else: either a different module at a stated version, or a directory on disk. The build then compiles that code instead of the version the proxy would serve.

open as a page

What does `go mod tidy` change in a module's go.mod, and when do you run it?

level: juniorimportance: must knowfreq 78%
basics
~20 s

go mod tidy makes the require block match the code: it adds a requirement for every module your packages import, drops requirements nothing imports any more, maintains the indirect markers, and syncs go.sum. Run it after changing imports.

open as a page

Why must a Go module's path and its import paths end in /v2 once it releases v2.0.0?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Go treats each major version as a separate module. From v2 on, the module line in go.mod and every import of its packages must end in /v2, so v1 and v2 can live in one build.

open as a page

What does `go get -u ./...` do in a Go module, and how does `-u=patch` differ?

level: juniorimportance: must knowfreq 58%
basics
~20 s

go get -u ./... upgrades every module behind the packages your module imports, directly or transitively, to its newest minor or patch release. go get -u=patch caps each move at the newest patch of the minor already selected.

open as a page

If your go.mod requires example.com/lib v1.2.0 and v1.9.0 is now released, which version does `go build` use?

level: juniorimportance: must knowfreq 62%
basics
~20 s

The build uses v1.2.0. Go's minimal version selection takes the highest version some go.mod in the graph actually requires, never the newest one published. A new release stays invisible to the build until a require line names it.

open as a page

What does a `//go:build linux` line at the top of a Go file do, and where must it appear?

level: juniorimportance: must knowfreq 50%
basics
~20 s

It is a build constraint. The file is compiled only when the target operating system is Linux, and is skipped entirely otherwise. The line must sit above the package clause, with a blank line after it.

open as a page

What is the difference between go build, go run and go install for a main package?

level: juniorimportance: must knowfreq 78%
basics
~20 s

go build compiles a main package and writes the executable into the current directory. go run builds it to a temporary file, runs it, then deletes the binary. go install writes the executable into GOBIN, which defaults to GOPATH/bin.

open as a page

Why is a second `go build` of unchanged Go code so much faster than the first, and where does the toolchain keep what it reuses?

level: juniorimportance: must knowfreq 50%
basics
~20 s

The go command caches compiled package output keyed by a hash of every input. Unchanged code hashes the same, so the second build reuses the stored result instead of recompiling. Running go env GOCACHE prints the directory that holds it.

open as a page

What does a //go:generate comment in a Go source file do, and when does it run?

level: juniorimportance: must knowfreq 62%
basics
~20 s

A //go:generate line is just a comment; no build step reads it. Only the go generate command scans for these lines and runs each named command in the package directory. go build and go test never run them, so the generated output must be committed.

open as a page

What does gofmt do to a Go source file, and why does it have no style options?

level: juniorimportance: must knowfreq 72%
basics
~20 s

gofmt reprints a Go file in one canonical layout: tabs for indentation, blanks for alignment, fixed spacing and brace placement, and import specs sorted inside each existing block. It exposes no style settings, so formatting stops being a review topic.

open as a page

How do you cross-compile a Go binary for Linux arm64 from a macOS laptop?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Set GOOS and GOARCH for that one build: GOOS=linux GOARCH=arm64 go build ./cmd/tool. The Go toolchain compiles for every target it supports on its own, so there is no separate cross-compiler, VM or target SDK to install.

open as a page

What does go build -ldflags "-X main.version=1.4.0" do to a Go binary?

level: juniorimportance: must knowfreq 72%
basics
~20 s

It tells the Go linker to set the package-level string variable named version in package main to 1.4.0 when the binary is linked, so the compiled program can report that version without it being hard-coded in the source.

open as a page

What does building with CGO_ENABLED=0 change about a Go binary, and what do you give up?

level: juniorimportance: must knowfreq 70%
basics
~20 s

CGO_ENABLED=0 disables cgo, so no C code is compiled in and the standard library uses its pure-Go net and os/user code. The result is a self-contained static binary that needs no C library on the host.

open as a page

A Go binary built on a glibc host dies on a musl host with "no such file or directory" — why?

level: seniorimportance: must knowfreq 55%
basics
~20 s

The binary was linked with cgo enabled, so it is dynamically linked and names a glibc dynamic loader such as /lib64/ld-linux-x86-64.so.2. That path does not exist on a musl host, so exec fails and reports the missing interpreter.

open as a page

Why does a Go file named watch_linux.go disappear from a windows/amd64 build?

level: middleimportance: should knowfreq 44%
basics
~20 s

The go tool reads the platform out of the filename: a file ending in _linux.go is compiled only when GOOS=linux. Building for Windows drops it from the package entirely, so every symbol it declared becomes undefined.

open as a page

Why does go/parser.ParseFile need a token.FileSet, and what does it return?

level: juniorimportance: must knowfreq 40%
basics
~20 s

go/parser.ParseFile returns an *ast.File, the syntax tree of one source file, plus an error. Node positions are bare integers; the token.FileSet holds each file's name and line table, so those integers decode to file, line and column.

open as a page

In golang.org/x/tools/go/analysis, what is an *analysis.Analyzer made of, and how does its Run function report a finding?

level: middleimportance: must knowfreq 40%
basics
~20 s

An analysis.Analyzer is a struct: Name, Doc, Requires and a Run function. Run is called once per package and calls pass.Reportf with a source position for each finding. A non-nil error from Run means the analyzer itself failed.

open as a page

In a custom go vet analyzer, what does pass.TypesInfo give you that the syntax tree alone cannot?

level: middleimportance: should knowfreq 32%
basics
~20 s

pass.TypesInfo is the package's *types.Info: it maps each identifier to the declaration it resolves to and each expression to its type. That is how a check recognises context.TODO whatever the import is aliased to, and ignores an unrelated TODO.

open as a page

How do ast.Inspect and ast.Walk differ, and what stops a traversal descending into children?

level: middleimportance: should knowfreq 32%
basics
~20 s

ast.Walk drives an ast.Visitor whose Visit returns a visitor for the children, or nil to skip them. ast.Inspect wraps that in a func(ast.Node) bool where false skips children. Both call you again with a nil node when a subtree ends.

open as a page

A custom vet analyzer every repo runs has reported nothing for a quarter. How do you prove it still fires?

level: seniorimportance: should knowfreq 22%
basics
~20 s

Treat silence as a failure until proven otherwise. Prove the matcher on an analysistest fixture with want comments, then work up the chain: analyzer linked into the shipped binary, packages actually analysed, files not hidden by build constraints, results not served from cache.

open as a page

What does the `go 1.22` line in a module's go.mod declare, and is it the Go version you must have installed?

level: juniorimportance: must knowfreq 60%
basics
~20 s

The go line names the minimum Go release the module needs and the language version its files compile under. It is a floor, not the exact compiler you run: any newer Go release builds the module fine, and still applies the older language version.

open as a page

Your machine has Go 1.24 installed and go.mod says `go 1.27` — why does `go build` still succeed?

level: juniorimportance: must knowfreq 50%
basics
~20 s

Because GOTOOLCHAIN defaults to auto: the go line in go.mod is a minimum, not a maximum, so the go command downloads a newer Go toolchain as a module and re-executes your build with it instead of failing.

open as a page

What does the GODEBUG environment variable control, and how is its value formatted?

level: juniorimportance: should knowfreq 36%
basics
~20 s

GODEBUG carries comma-separated name=value settings, such as panicnil=1, that switch particular runtime and standard-library behaviours back to an older Go release's semantics. A Go binary reads them when it starts, so no rebuild is needed.

open as a page

What does the Go 1 compatibility promise guarantee when you move to a newer Go toolchain?

level: juniorimportance: should knowfreq 38%
basics
~20 s

Go 1 promises that source building and running correctly under one Go 1.x release keeps building and running under later ones. It binds the language specification and the documented standard-library API, so upgrading is normally just a recompile.

open as a page

A module with `go 1.21` in go.mod is built by Go 1.25 — does `for i := 0; i < 3; i++ { go func() { fmt.Println(i) }() }` share one `i`?

level: middleimportance: should knowfreq 42%
basics
~20 s

Yes, one shared i. Per-iteration loop variables arrived in Go 1.22 and are gated on the module's go line, not on the installed release. A go 1.21 line keeps Go 1.21 semantics, so all three goroutines close over the same variable.

open as a page