Build Cache and Reproducibility
Build Cache and Reproducibility
Overview
The Go toolchain caches build actions aggressively. Understanding the cache explains “why CI rebuilt everything” and how to aim for bit-reproducible artifacts.
Diagram: Reproducible build
sources + flags + go version
│
v
GOCACHE
│
v
objects ──► link (-trimpath) ──► binary
Cache Location
go env GOCACHE
go clean -cache
go clean -modcache # modules, separateCache keys include source, build flags, env that affects compile, cgo toolchains, tags, GOOS/GOARCH, etc.
What Busts Cache
- Touching files unnecessarily
- Changing
CGO_*flags - Unstable generated code (timestamps in source)
- Different Go patch versions
-trimpathvs not when comparing binaries
Reproducible Flags
go build -trimpath -ldflags='-buildid= -s -w' -o app .| Flag | Effect |
|---|---|
-trimpath |
Remove local paths from binaries |
-buildid= |
Empty buildid for stabler hashes |
-s -w |
Strip symbols (optional) |
CGO_ENABLED=0 |
Fewer host dependencies |
Module Reproducibility
go mod download
go mod verify
go build -mod=readonly
# or
go build -mod=vendorLock with go.sum. Pin toolchain in go.mod for compiler version policy.
Experiment
go mod init example
echo 'package main; func main(){}' > main.go
go build -trimpath -ldflags='-buildid=' -o a1 .
go build -trimpath -ldflags='-buildid=' -o a2 .
shasum a1 a2 # often identical pure-GoWhat to notice: Pure Go + trimpath often matches; cgo and ld versioning frequently break reproducibility.
Try next: In CI, print go version, go env, and go list -m all on mismatch incidents.