goenv: Manage Go Versions in CI
goenv install <version> installs a Go toolchain and goenv local writes .go-version, with shims pointing go at the selected version and setting GOROOT.
goenv brings the rbenv shim model to Go. It manages GOROOT for you, which is the main thing to get right in CI because many Go tools resolve the standard library through it.
What it does
goenv installs multiple Go versions and switches between them with shims. It selects the version from .go-version (local), the global setting, or GOENV_VERSION, and points GOROOT at that install so the standard library matches the active toolchain.
Common usage
export GOENV_ROOT="$HOME/.goenv"; export PATH="$GOENV_ROOT/bin:$PATH"
eval "$(goenv init -)"
goenv install 1.22.3
goenv local 1.22.3 # writes .go-version
go versionOptions
| Command / flag | What it does |
|---|---|
| goenv install <v> | Install a Go version |
| goenv install -s <v> | Skip if already installed |
| goenv local <v> | Write .go-version for this directory |
| goenv global <v> | Set the default Go version |
| GOENV_GOPATH_PREFIX | Control GOPATH layout per version |
| eval "$(goenv init -)" | Add shims and manage GOROOT |
In CI
Eval goenv init - in each step so GOROOT and PATH are set. Cache ~/.goenv/versions. Note that Go 1.21+ also has a built-in toolchain mechanism (the go directive in go.mod can auto-download a newer toolchain), which can interact with goenv; set GOTOOLCHAIN=local if you want goenv to be the only thing choosing the version.
Common errors in CI
"goenv: go: command not found" means init was not eval'd (shims/PATH not set). "version 1.22.3' is not installed" means the pin is uninstalled; run goenv install. A build using an unexpected Go version may be Go 1.21+ auto-downloading a toolchain per go.mod; set GOTOOLCHAIN=local`. Wrong stdlib errors usually mean GOROOT was set manually and conflicts with goenv.