Caching Go module downloads with a named volume
By default the Go module cache ($GOPATH/pkg/mod) and build cache live inside the container’s writable layer, so every DevContainer rebuild discards them and the next go build re-downloads and recompiles the entire dependency graph. This page moves both caches into named volumes so rebuilds are near-instant and offline-capable. It extends the Go Development Environment with gopls & Modules cluster.
Prerequisites
- Go 1.22+ in the container
- A non-root
remoteUser(e.g.vscode) that owns the cache paths - Docker named-volume support
How-To Steps
-
Mount the module and build caches as named volumes and point Go at them:
{ "image": "mcr.microsoft.com/devcontainers/go:1.22@sha256:b91a...", "containerEnv": { "GOPATH": "/home/vscode/go", "GOCACHE": "/home/vscode/.cache/go-build" }, "mounts": [ "source=go-mod-cache,target=/home/vscode/go/pkg/mod,type=volume", "source=go-build-cache,target=/home/vscode/.cache/go-build,type=volume" ], "remoteUser": "vscode" } -
Fix ownership of the mounted volumes on first create, since fresh volumes are root-owned:
{ "postCreateCommand": "sudo chown -R vscode:vscode /home/vscode/go /home/vscode/.cache/go-build" } -
Warm the cache once so subsequent rebuilds reuse it:
go mod download go build ./... -
Confirm a rebuild reuses the cache — recreate the container and time a build:
devcontainer up --workspace-folder . --remove-existing-container devcontainer exec --workspace-folder . bash -c "time go build ./..." # second build should be seconds, not minutes
Common Pitfalls
| Symptom | Root Cause | Remediation |
|---|---|---|
| Cache empty after every rebuild | Cache in the container layer, not a volume | Mount pkg/mod and go-build as named volumes |
permission denied writing cache | Fresh volume owned by root | chown the paths in postCreateCommand |
| Build still slow on second run | GOCACHE not redirected to the volume | Set GOCACHE in containerEnv |
| Stale module versions served | Cache holds a yanked version | go clean -modcache once, then re-download |
Conclusion
The invariant: both GOPATH/pkg/mod and GOCACHE must live on persistent named volumes the remoteUser owns. Redirect them with containerEnv, fix ownership once, and rebuilds reuse every download and compiled object instead of starting cold.
FAQ
Why two volumes instead of one?
The module cache (pkg/mod) holds downloaded source; the build cache (GOCACHE) holds compiled objects. They grow and invalidate independently, so separate volumes keep eviction clean.
Can I share these volumes between projects? Yes — the module cache is content-addressed and safe to share. The build cache is also keyed by content, so cross-project sharing is correct and saves recompilation.
Related
- Go Development Environment with gopls & Modules — the parent cluster.
- Configuring gopls module proxy in an air-gapped container — resolving modules offline.
- Cross-compiling Go binaries inside containers — reusing the cache across target architectures.