Build Cache and Reproducibility

Updated

September 8, 2026

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, separate

Cache 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
  • -trimpath vs 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=vendor

Lock 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-Go

What 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.