Manage multiple versions of the Go programming language
How to install, manage, and switch between multiple Go versions using official tools and custom shell functions.
Installing Go
All versions of Go are available to download here: https://go.dev/dl/
The installation directory will be: /usr/local/go.
Once you have Go installed, you can then use the go command to either install go based tools/binaries or other versions of Go.
💡 TIP
Additionally, you can automate the install via a terminal using the following shell function (only tested on macOS):
# you can swap `ag` for `grep` if you prefer
alias golatest="curl -L https://github.com/golang/go/tags 2>&1 |\
ag '/golang/go/releases/tag/go[\w.]+' -o | cut -d '/' -f 6 | awk NR==1 | ag '\d.+' -o"
function go_install {
if [ -z "$1" ]; then
echo USAGE: go_install 1.18.1 OR go_install \$\(golatest\)
return
fi
v=$1
osname=$(uname -s | tr '[:upper:]' '[:lower:]')
hardware=$(uname -m)
mkdir -p ~/goversions
if ! test -f "~/goversions/go$v.$osname-$hardware.pkg"; then
printf "\nDownloading %s\n\n" "go$v.$osname-$hardware"
curl -L -o ~/goversions/go$v.$osname-$hardware.pkg https://go.dev/dl/go$v.$osname-$hardware.pkg
fi
echo ""
sudo rm -rf /usr/local/go; sudo installer -pkg ~/goversions/go$v.$osname-$hardware.pkg -target /usr/local/
clear
go version
}
Installing binaries
As of version go 1.16 go install is now responsible only for installing binaries, not modifying a go.mod file (that’s what go get is for).
go install example.com/cmd@v1.0.0
go install example.com/cmd@latest
💡 TIP
Installing different go versions
The following is the ‘official’ approach…
💡 TIP
go install golang.org/dl/go1.18@latest
go1.18 download
go1.18 version # go version go1.18 darwin/amd64
alias go=go1.18
If you want a simple binary overwrite of the global go command (for example, an alias doesn’t work with Makefiles that reference go because make targets run in a subshell):
go install golang.org/dl/go1.18@latest
go1.18 download
sudo cp $(which go1.18) $(which go)
ℹ️ INFO
This requires sudo as it’s copying into /usr/local/....
If you want the latest ‘tip’ release (and maybe with additional/unreleased features, at the time of writing that might have included something like ‘fuzzing’ which was made available in go1.18):
go install golang.org/dl/gotip
gotip download dev.fuzz # also download a dev/tip specific tool/feature
gotip test -fuzz=FuzzFoo
Basic switcher using go.mod as reference
# This function identifies the go version specified in a project's go.mod
# It then attempts to switch to a binary of that version.
# If none exists it will instruct you how to download it.
#
# NOTE: Some tools, e.g. TinyGo, won't work with this approach because we're
# just replacing the go binary and the VERSION file, where the originally
# installed version of go will have things like CGO files that TinyGo will try
# to use and if those don't align with the version of the binary we've switched
# to, then it means TinyGo will fail to compile.
#
# In that scenario you're better off using the `go_install` shell function
# approach at the top of the page.
function go_version {
if [ -f "go.mod" ]; then
v=$(grep -E '^go \d.+$' ./go.mod | grep -oE '\d.+$')
if [[ ! $(go version | grep "go$v") ]]; then
echo ""
echo "About to switch go version to: $v"
if ! command -v "$HOME/go/bin/go$v" &> /dev/null
then
echo "run: go install golang.org/dl/go$v@latest && go$v download && sudo cp \$(which go$v) \$(which go)"
return
fi
sudo cp $(which go$v) $(which go)
echo -n go$v | sudo tee $(dirname $(dirname $(which go)))/VERSION > /dev/null
fi
fi
}
# To support the configuring our go environment we will override the cd
# command to call the go logic for checking the go version.
#
# NOTE: We use `command` and not `builtin` because the latter doesn't take into
# account anything available on the user's $PATH but also because it didn't
# work with the Starship prompt which seems to override cd also.
function cd {
command cd "$@"
RET=$?
go_version
return $RET
}
Unofficial: goenv
https://github.com/syndbg/goenv
The nice thing about goenv is that it lets you more easily automate a switch between projects using either GOENV_VERSION or .go-version (docs).