How to Install Go and Manage Versions on Linux the Safe Way
Install Go on Linux from the official tarball: verify the checksum, extract to usr local, set PATH, and let GOTOOLCHAIN fetch versions a project needs.

The Go that your package manager ships is often a year or more behind, and a new project may need the current release. The official method is a tarball and a line in your profile, which takes two minutes and is easy to repeat for upgrades. This post also covers how modern Go manages versions on its own. It sits beside go run as a script runner in the Go toolbox. Commands used Go 1.24 on Debian 13 (amd64).
Download and verify
VERSION=1.24.0
cd /tmp
curl -fsSLO "https://go.dev/dl/go${VERSION}.linux-amd64.tar.gz"
sha256sum "go${VERSION}.linux-amd64.tar.gz"Compare the printed hash with the one on the download page, which lists a SHA-256 beside each file. Do the comparison with your eyes or with echo "HASH file" | sha256sum -c, using the hash copied from the site rather than from the same download location. This guards against a corrupted or tampered download; see verifying downloads. Use linux-arm64 on ARM machines; uname -m tells you which you have.
Install, replacing the old one
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf "go${VERSION}.linux-amd64.tar.gz"
/usr/local/go/bin/go versiongo version go1.24.0 linux/amd64
Removing first matters: extracting a new release over an old one leaves stale files from the previous version, which can break builds in confusing ways. Use sudo only for these two commands; Go itself runs fine as a regular user.
Set up PATH
cat >> ~/.profile <<'EOF'
export PATH="$PATH:/usr/local/go/bin:$HOME/go/bin"
EOF
. ~/.profile
go version
go env GOPATH GOROOT/usr/local/go/bin holds go and gofmt. $HOME/go/bin is where go install example.org/tool@latest places binaries, so you want it on the path too. Putting the line in ~/.profile covers login shells; for interactive terminals that do not read it, add it to ~/.bashrc as well. Check that scripts and cron see it, since they do not read your interactive files.
Let Go pick the version
module example.org/tool
go 1.23.0
toolchain go1.23.4
Since Go 1.21 the go line is a minimum requirement, and the toolchain line names a preferred version. If your installed Go is older than the project needs, the command downloads the required toolchain into the module cache and runs it, controlled by GOTOOLCHAIN. The default auto allows this; GOTOOLCHAIN=local forbids it, which suits offline machines and CI that must not download. For a specific older version on demand: go install golang.org/dl/go1.22.8@latest && go1.22.8 download.
Upgrade
Repeat the three steps with the new version. Keep the previous tarball if you may need to roll back. Distribution packages and snap are fine for casual use, but they track their own schedule: sudo apt install golang-go may give a release that predates the one your go.mod wants, which then triggers a toolchain download anyway.
Where this does not apply
On a shared multi-user machine, a central install under /usr/local is right; on a single-user laptop, a per-user directory such as ~/.local/go avoids sudo. Containers should use the official golang image. If you work across many Go versions daily, a manager like mise can switch them per directory; see mise and asdf.
Why the tarball and not the distribution package
Distribution repositories carry a Go version that was current when the release was frozen, and it falls behind. Debian and Ubuntu packages often lag by several minor releases, and a project that asks for a recent version in go.mod fails to build against them. The official tarball from go.dev/dl gives you a current release, and the layout is simple: everything lives under one directory, normally /usr/local/go, with no installer scripts and no system packages involved. Installing a new release means replacing that directory, and removing Go means deleting it. The same property makes it easy to keep several versions side by side in separate directories and switch with the PATH, or with a version manager. The trade-off is that nothing updates it for you, so security releases are something you have to notice.
Go's support policy covers the two most recent major releases, so the one you installed a year ago may no longer receive security fixes. Subscribe to the release announcements or check the download page at intervals.
Verifying what you downloaded
The download page lists a SHA-256 checksum for each archive, and the file go.dev/dl/?mode=json provides the same data for scripts. Compare the checksum of the file you downloaded with sha256sum before you unpack it. This catches a corrupted download. It protects against tampering only if the checksum comes through a different path than the file, which is weak when both come from one site over one connection, though TLS gives reasonable assurance. Do the download over HTTPS only, and never pipe a download into a shell. In an automated setup, keep the expected checksum in your repository next to the version number, so changes to either are a visible commit that someone reviews, and fail the build if they do not match. Go modules have their own protection, since the module proxy and checksum database verify dependencies, which covers the code you import and not the toolchain itself.
Upgrades, toolchains and common problems
Go 1.21 introduced toolchain management. The go command reads the go and toolchain lines in go.mod, and when the project needs a newer version than the installed one, it downloads that toolchain into the module cache and uses it, verified through the checksum database. This means an old installed version can still build a project that requires a newer one, and it also means a build can fetch a toolchain without you noticing. Set GOTOOLCHAIN=local to forbid downloads in locked-down environments, and GOTOOLCHAIN=auto is the default. When a build behaves unexpectedly, run go version and go env GOROOT to see which toolchain is in use.
To upgrade, remove the old directory first, then extract the new archive. Extracting on top of an old tree can leave stale files from the previous version and cause strange build errors. Check that the PATH contains the Go bin directory and that no older go binary from a package shadows it, which type -a go reveals.
Putting it in a script for many machines
For servers and CI images, wrap the steps in a small script that takes the version as an argument. Download the archive and the checksum, compare, remove the old directory, extract, and print go version at the end. Make it idempotent: if the installed version already matches, do nothing. Pick the archive name from the machine's architecture, mapping x86_64 to amd64 and aarch64 to arm64, since the download names use the Go architecture names. Run as root only for the copy into the system directory, and keep the download in a temporary directory that is cleaned up afterwards. In containers, use the official Go images for builds, which saves the whole procedure.
See Go's installation instructions and Go Toolchains.


