SysTutorials

Managing Multiple Go Versions on Ubuntu

· updated April 11, 2026

When you need a specific Go version on Ubuntu, the default package manager often lags behind. Production systems like Kubernetes, Hyperledger Fabric, and other projects frequently require versions newer than what’s available in standard repositories. This guide covers system-level installation that allows multiple versions to coexist.

Remove existing Go installations

Start by cleaning up any existing Go packages to prevent conflicts:

sudo apt remove 'golang-*'

Check for and remove any manually installed Go directories:

sudo rm -rf /usr/local/go /usr/local/go-*

Download and verify the Go release

Visit the official Go downloads page to find your required version. For x86_64 Ubuntu systems, download the binary archive and its checksum file:

wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz.sha256

Verify integrity before extracting:

sha256sum -c go1.23.4.linux-amd64.tar.gz.sha256

The output should display go1.23.4.linux-amd64.tar.gz: OK.

For other architectures, adjust the filename accordingly:

Extract and install

Extract the tarball to a temporary location and move it to a versioned directory in /usr/local:

tar xf go1.23.4.linux-amd64.tar.gz -C /tmp
sudo mv /tmp/go /usr/local/go-1.23.4

Using a versioned directory name simplifies maintaining multiple Go installations side-by-side.

Configure environment variables

Create /etc/profile.d/Z99-golang.sh with the following content:

export GOROOT=/usr/local/go-1.23.4
export PATH=$GOROOT/bin:$PATH

The Z99- prefix ensures this script runs after other profile.d scripts, preventing PATH overrides.

Apply the changes immediately:

source /etc/profile.d/Z99-golang.sh

For subsequent login sessions, the environment variables will be sourced automatically.

Verify the installation

Check which Go binary is in your PATH:

which go

Confirm the installed version:

go version

Inspect the full environment:

go env

Verify that GOROOT points to /usr/local/go-1.23.4 and GOBIN is empty (defaults to $GOPATH/bin).

Managing multiple Go versions

Install multiple versions by repeating the download and extraction steps with different version numbers:

# Download and extract Go 1.22.0
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
tar xf go1.22.0.linux-amd64.tar.gz -C /tmp
sudo mv /tmp/go /usr/local/go-1.22.0

# Download and extract Go 1.23.4
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
tar xf go1.23.4.linux-amd64.tar.gz -C /tmp
sudo mv /tmp/go /usr/local/go-1.23.4

Create separate profile.d scripts for each version:

echo 'export GOROOT=/usr/local/go-1.23.4; export PATH=$GOROOT/bin:$PATH' | sudo tee /etc/profile.d/Z99-go-1.23.4.sh
echo 'export GOROOT=/usr/local/go-1.22.0; export PATH=$GOROOT/bin:$PATH' | sudo tee /etc/profile.d/Z99-go-1.22.0.sh

To switch versions, update the active symlink:

sudo ln -sf Z99-go-1.23.4.sh /etc/profile.d/Z99-golang.sh
source /etc/profile.d/Z99-golang.sh
go version

Alternatively, manually edit /etc/profile.d/Z99-golang.sh and source it again.

Working with Go modules

Go 1.13+ uses module mode by default. Create a workspace structure:

mkdir -p ~/go/projects
cd ~/go/projects
go mod init github.com/username/project

The GOPATH is less critical now, though ~/go remains the default workspace. Go will create go.mod and go.sum files to manage dependencies.

For organization across multiple projects, use Go workspaces (1.18+):

go work init
go work use ./project1 ./project2

This allows testing changes across multiple modules without publishing intermediate versions.

Non-interactive shell environments

Cron jobs and systemd services don’t source /etc/profile.d/ by default, so you need to configure them explicitly.

For systemd services, set environment variables in the unit file:

[Service]
Environment="GOROOT=/usr/local/go-1.23.4"
Environment="PATH=/usr/local/go-1.23.4/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"

For cron jobs, explicitly source the profile in your script:

#!/bin/bash
source /etc/profile.d/Z99-golang.sh
go build ./...

Troubleshooting

Go still points to the old version: Check your shell’s startup files. Bash reads ~/.bashrc and zsh reads ~/.zshrc — ensure no conflicting PATH definitions override /etc/profile.d/. Verify with:

echo $PATH
which go

If you see an unexpected path, check shell RC files:

grep -n "export GOROOT\|export PATH.*go" ~/.bashrc ~/.zshrc

Permission errors during extraction: Always extract to a temporary directory first, then move with sudo:

tar xf go1.23.4.linux-amd64.tar.gz -C /tmp
sudo mv /tmp/go /usr/local/go-1.23.4

Checksum verification fails: Ensure you downloaded both the archive and checksum file in the same directory. Re-download if the file may be corrupted:

rm -f go1.23.4.linux-amd64.tar.gz*
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz.sha256
sha256sum -c go1.23.4.linux-amd64.tar.gz.sha256

Runtime issues with CGO: If you’re using cgo (C/C++ bindings), ensure you have the necessary build tools installed:

sudo apt install build-essential pkg-config
← All posts