Repository navigation
cmd/go: build cache management #81830
Description
build cache primer
cache structure
The go build cache stores action and data entries used by various go commands.
The cache is structured as:
$GOCACHE/
├── 00/
│ ├── <64-hex-ActionID>-a
│ ├── <64-hex-OutputID>-d
│ └── <64-hex-OutputID>-d/
│ └── <binary_name>
├── ...
├── fuzz/
│ └── <import/path>/
│ └── ...
├── trim.txt
├── testexpire.txt
In particular:
trim.txtrecords the last time the build cache was trimmedtestexpire.txtrecords a cutoff date for useable test cache artifacts (go clean -testcachedoesn't actually delete test cache entries)
adding to the build cache
cache keys are a hex sha256 hash of cache inputs.
This does mean that we can't know what is cached merely from looking at the cache entry.
Data entries should take up the most space, and each should have a corresponding Action entry,
but the action entry currently only records the hash mapping of action to output without additional details.
ai summary of artifacts and cache keys
3. What Goes into the Cache Key for Each Type of Cached Artifact?
Cache keys (ActionID) are 32-byte salted SHA-256 hashes generated by NewHash. Every hash starts with hashSalt (gover.LocalToolchain()), guaranteeing that different Go toolchain versions or development commits never collide on action keys. Derived subkeys use Subkey(parent, desc) = SHA256("subkey:" + parent + desc).
A. Package Compilation Action Key (Builder.buildActionID)
- Salt:
hashSalt - Tag:
compile\n - Package origin: package directory (if outside GOROOT and not trimmed), or
module <path>@<version>(if-trimpath) - Language version:
go <version>fromgo.mod - Platform:
goos <GOOS> goarch <GOARCH> - Package metadata:
import <ImportPath>,omitdebug,standard,local,prefix,trimpath,forcelibrary - C toolchain configuration: C compiler ID, compiler flags, and toolchain hashes if package uses cgo (
addCToolchainIDs) - Coverage:
cover <mode> <toolID("cover")>(if coverage instrumentation enabled) - Fuzzing: fuzz instrumentation flags (if fuzzing enabled)
- Module build info:
modinfo <string> - Toolchain-specific configuration:
- For
gc: compiler tool ID (b.toolID("compile")), forced gcflags, package gcflags; asm tool ID, forced asmflags, package asmflags (if.sfiles present); architecture environment variables (GOAMD64,GOARM,GOMIPS, etc.); cleanGOEXPERIMENT; compiler debug env vars (GOCLOBBERDEADHASH,GOSSAFUNC,GOSSADIR,GOCOMPILEDEBUG) - For
gccgo: gccgo tool ID, flags, package path, ar tool ID, assembler tool ID
- For
- Input file contents: file path and SHA-256 content hash (
FileHash) of everyGoFiles,CgoFiles,CFiles,CXXFiles,FFiles,MFiles,HFiles,SFiles,SysoFiles,SwigFiles,SwigCXXFiles, andEmbedFiles. - Dependency export data: for each direct imported dependency,
import <ImportPath> <buildExportID(dep.buildID)>(using the content ID of the dependency's export data, not its action ID, enabling convergence in circular bootstrapping). - Preprocessed PGO profile:
pgofile <fileHash(pgoProfile)>(if PGO enabled).
B. Link Action Key (Builder.linkActionID)
- Salt:
hashSalt - Tag:
link\n - Platform and mode: resolved
buildmode,goos <GOOS>,goarch <GOARCH> - Package metadata:
import <ImportPath>,omitdebug,standard,local,prefix,defaultgodebug,trimpath - Linker configuration: linker tool ID (
b.toolID("link")), forced ldflags, package ldflags, arch env variables, cleanGOEXPERIMENT, GOROOT (or empty if-trimpath),GO_EXTLINK_ENABLED - Dependency packages: for every dependency action
a1,packagefile <ImportPath>=<buildObjectID(a1.buildID)>(content ID of package object data). - Main package ID:
packagemain <buildActionID>/<buildObjectID>(ensures the binary's embedded build ID matches). - Shared libraries:
packageshlib <ImportPath>=<buildObjectID(shlib)>(if linking against shared libraries).
C. Separate Export Action Key (Builder.exportActionID)
- Salt:
hashSalt - Export tool ID:
b.toolID("export") importPath,compiler,goVersion- Content hashes of all Go source files
- Export content IDs of dependent packages (
packageFile <ImportPath>=<buildExportID(dep.buildID)>).
D. Vet Analysis Key (Builder.vet)
- Salt:
hashSalt - Vet tool ID:
b.toolID("vet") - Active vet checker flags (
vetFlags) - Root package compile action ID:
pkg <a.Deps[0].actionID> - Content hashes of
.vetxfact export files of all dependencies (vetout <ImportPath> <fileHash(vetx)>). - Subkeys:
- Fix archive:
cache.Subkey(id, "fix.zip") - Output stdout:
cache.Subkey(id, "stdout")
- Fix archive:
E. Test Result Keys (Two-Level Architecture)
- Level 1 Key (
testID) (runTestActor.Act):hashSalt- Content ID of test executable (or linker action ID proxy)
id - Test command line flags (
cacheArgs) - Exec command runner (
work.ExecCmd) - Value stored: test execution log (
# test log).
- Level 2 Key (
testInputsID) (computeTestInputsID):
Computed by parsing the recorded# test log:env GODEBUG <hash>getenv <var>: hash of environment variable existence and valuechdir <path>: stat hash of directorystat <path>: file stat info (size, mode, mtime, isDir)open <path>: file stat info (plus directory entry stats if directory; rejects caching if modified< 2sago viaerrFileTooNew)
- Lookup Keys:
- Test output stdout/stderr:
testAndInputKey(testID, testInputsID)=cache.Subkey(testID, "inputs:" + hex(testInputsID)). - Coverage profile:
coverProfileAndInputKey(testID, testInputsID, covMeta)=cache.Subkey(testID, "coverProfile:" + hex(testInputsID) + ...).
- Test output stdout/stderr:
F. Cgo Run & Compile Keys
cgoRunActionID(exec.go): cgo tool ID,GOOS,GOARCH, import path, package directory, C/C++/Fortran compiler flags, msan/asan flags, export header flag, and hashes of Cgo/SWIG files.cgoCompileActionID(exec.go):GOOS,GOARCH, source file name and content hash, compiler flags, package origin, trimpath flag, C toolchain IDs.- Subkeys: Intermediate object files stored under
cache.Subkey(actionID, filename).
G. Preprocessed PGO Profile Key (Builder.pgoActionID)
- Salt:
hashSalt - Preprofile tool ID:
b.toolID("preprofile") - Content hash of raw input pprof file (
b.fileHash(input)).
H. C Compiler Flags & Compiler ID
gccCompilerID(exec.go): Hash of compiler binary path, stat info of compiler binaries, and probed internal compiler ID.gccSupportsFlag:cache.Subkey(compilerID, "gccSupportsFlag " + flag).
I. Module Index Keys (modindex)
- Module hash:
runtime.Version(), index format version,modroot. - Package hash:
runtime.Version(), index format version,modroot,pkgdir, directory entries and stat info (rejects caching if mtime is within 2 seconds).
removing from the build cache
On every command exit, trim.txt is checked.
Cache trimming runs at most once per day.
Entries with mtime older than 5 days are removed.
Accessing a cache entry updates mtime (not atime).
go clean -cache drops the entire cache:
- concurrent
cleanandbuildis unsafe cmd/go: concurrent build and cache clean is unsafe #31948 - cache can be trimmed while still in use cmd/go: invoking go run from go test can corrupt build cache #69566
problems people have
cache doesn't cache enough
- cache test binaries proposal: cmd/go: add flag option to control whether linked binary is put in build cache #77349
- cache should persist for longer (to have a warm cache in containerized / reproducible builds) proposal: cmd/go: allow disabling build cache trimming #69565
cache caches too much
- caches large embedded resources proposal: cmd/go: option to disable caching for specific packages #59683
- generics bloats build cache, in a low level dep cmd/go: build cache grows abnormally large (100GB+) and go build -x -v shows full recompilation with very slow initial build (more than 5 min) #76946
- make.bash cache entries all: repeatedly running all.bash in an unchanged tree grows the Go build cache without limit #61484
- runs out of disk space
- compress the build cache cmd/go: compress GOCACHE #76337
- clean the build cache based on size (absolute limit, disk relative limit) cmd/go: clean GOCACHE based on disk usage #29561
- cache trimming takes a long tim cmd/go: trim build cache incrementally #38939
what to do?
A size based cached could solve both wanting to cache more, and caching too much.
But it would be adversely affected by storing a lot of recent large binaries (e.g. lots of test runs).
A generational cache like https://go.dev/cl/433295 could let us prune churning entries more effectively.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsTodo
Activity
gabyhelp commentedon Sep 28, 2026
Related Issues
Related Code Changes
Related Documentation
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
prattmic commentedon Sep 29, 2026
cc @golang/command-line @matloob @thepudds