gocachez is a GOCACHEPROG
helper for the Go build cache. It stores cache artifacts as zstd-compressed
files, materializes uncompressed files for the Go command on demand, and evicts
old compressed entries automatically.
This project was inspired by the discussion on
golang/go#76337.
Go std:
| Mode | Cold time | Warm time | Disk usage |
|---|---|---|---|
No GOCACHEPROG |
36.31s | 4.06s | 1.60GB |
gocachez |
40.97s | 5.65s | 403MB |
| +4.66s (+12.8%) | +1.59s (+39.1%) | -74.8% |
| Mode | Cold time | Warm time | Disk usage |
|---|---|---|---|
No GOCACHEPROG |
89.20s | 4.76s | 4.95GB |
gocachez |
96.84s | 6.97s | 453MB |
| +7.64s (+8.6%) | +2.21s (+46.4%) | -90.9% |
Requires Go 1.25 or newer.
$ go install github.com/jakebailey/gocachez@latest
$ go env -w GOCACHEPROG=gocachezUndo:
$ go env -u GOCACHEPROGShow help:
$ gocachez -hRun as a GOCACHEPROG helper:
$ gocachezRemove inactive cache state:
$ gocachez cleanclean removes blobs, live files, and catalog state that no active gocachez
process is using. State for active live runs is preserved.
Show cache state:
$ gocachez statusstatus reports the current cache configuration and state.
gocachez implements the Go command's external cache protocol over stdin and
stdout. The Go command sends put requests when it wants to store an artifact
and get requests when it wants to retrieve one.
On put, gocachez:
- streams the artifact body into a zstd encoder,
- writes the compressed bytes into
blobs/, - writes the uncompressed body into the current run's
live/directory, and - returns that live file path to the Go command as
DiskPath.
The compressed blob is the durable cache entry. The live file is only the temporary uncompressed file the Go command needs in order to read the artifact from disk.
On get, gocachez looks up the action ID in SQLite. On a hit, it opens the
compressed blob, decompresses it into the current run's live/ directory, and
returns the materialized path as DiskPath.
Live files are removed when the GOCACHEPROG process closes. If gocachez
exits abnormally, a later run can safely clean up abandoned live files: each run
holds an OS file lock, and another process only reclaims a run directory after
it can acquire that lock.
Some live files can escape the Go command process through go list output. For
example, go list -export reports an Export path that tools such as
go/packages and golangci-lint may open after the Go command has closed its
GOCACHEPROG helper. go list -compiled can also report generated cgo source
paths in CompiledGoFiles, and go list -test can report a generated
_testmain.go path in the synthetic test main package's GoFiles.
To support those tools without keeping large uncompressed archives around,
gocachez treats these escaped files specially on close. Package archives are
replaced with small archives containing only their __.PKGDEF export data, and
generated Go source files that can appear in list output are retained as-is.
These retained files are stored under retained/, keyed by output ID, and are
cleaned up once no catalog entry references that output.
By default, gocachez reads its config from:
os.UserConfigDir()/gocachez/config.json
and stores cache data in:
os.UserCacheDir()/gocachez
See os.UserConfigDir and
os.UserCacheDir for the
platform-specific base directories.
Example config:
{
"cacheDir": "/path/to/gocachez",
"maxSize": "20GiB",
"maxAge": "5d",
"verbose": false
}Config can also be selected explicitly:
$ go env -w GOCACHEPROG="gocachez -config /path/to/config.json"Supported options:
Cache directory
- Config:
cacheDir - Environment:
GOCACHEZ_DIR - Flag:
-dir - Default:
os.UserCacheDir()/gocachez
Maximum compressed cache size
- Config:
maxSize - Environment:
GOCACHEZ_MAX_SIZE - Flag:
-max-size - Default:
20GiB;0disables size-based pruning.
Maximum age of unused entries
- Config:
maxAge - Environment:
GOCACHEZ_MAX_AGE - Flag:
-max-age - Default:
5d, matchingcmd/go'sGOCACHE;0disables age-based pruning. Accepts a duration such as5d,36h, or90m.
Age-based pruning is independent of maxSize: entries and retained files that
have not been used within maxAge are trimmed even while the cache is under its
size limit.
Verbose maintenance logs
- Config:
verbose - Environment:
GOCACHEZ_VERBOSE - Flag:
-v - Default:
false
Config file path
- Environment:
GOCACHEZ_CONFIG - Flag:
-config - Default:
os.UserConfigDir()/gocachez/config.json - Missing file is an error when explicitly set.