Skip to content

govm: Switch Between Go Versions Without the Headache

If you write Go code regularly across multiple projects, you have almost certainly run into this situation: one project pins to Go 1.22, another requires Go 1.23, and a third is cutting edge on whatever just shipped. Installing Go manually, updating your PATH by hand, and keeping track of which binary lives where is tedious and error-prone. A version manager removes all of that friction.

govm is a lightweight, open-source Go version manager built by Melkey. It ships both a polished terminal UI (TUI) and a clean command-line interface, installs Go releases directly from go.dev, and uses a shim-based approach to switch versions without touching your shell configuration after the initial setup. It has become a regular part of my toolbox as an open source developer who routinely jumps between Go releases.

The Problem with Managing Go Manually

The official Go distribution is a tarball you unpack to /usr/local/go (or wherever you choose). To run a different version, you need to:

  1. Download the new tarball from go.dev/dl.
  2. Unpack it somewhere.
  3. Update your $PATH to point to the new Go bin directory.
  4. Reload your shell.
  5. Remember to undo all of that when you switch back.

This process is manageable for one switch, but if you are working across many repositories with different Go requirements, it becomes noise that distracts from the actual work.

govm automates every step after the initial PATH setup. Once you add its shim directory to your PATH, version switching is a single command or a couple of keystrokes in the TUI.

Installation

Using go install

The fastest way to install govm is with go install. govm requires Go 1.23 or later:

go install github.com/melkeydev/govm@latest

After installation, run govm to launch the TUI.

Using Homebrew (macOS and Linux)

If you prefer Homebrew, add the tap and install:

brew tap melkeydev/tap
brew install govm

From Source

git clone https://github.com/melkeydev/govm.git
cd govm
go build -o govm

Then place the resulting binary somewhere on your PATH.

First-Time Setup

The first time you run govm, it walks you through adding its shim directory to your shell configuration. This is a one-time step.

Add the shim directory to your shell configuration:

echo 'export PATH="$HOME/.govm/shim:$PATH"' >> ~/.zshrc
source ~/.zshrc

For Bash users, replace ~/.zshrc with ~/.bash_profile or ~/.bashrc.

Add the shim directory to your shell configuration:

echo 'export PATH="$HOME/.govm/shim:$PATH"' >> ~/.bashrc
source ~/.bashrc

For Zsh, replace ~/.bashrc with ~/.zshrc.

Add the shim directory to your user PATH:

$shim = "$env:USERPROFILE\.govm\shim"
$existing = [Environment]::GetEnvironmentVariable("Path", "User")

if ($existing -notlike "*$shim*") {
    if ([string]::IsNullOrEmpty($existing)) {
        $newPath = $shim
    } else {
        $newPath = "$shim;$existing"
    }

    [Environment]::SetEnvironmentVariable("Path", $newPath, "User")
}

Then restart your terminal for the change to take effect.

Tip

govm installs Go versions to ~/.govm/versions and places wrapper scripts in ~/.govm/shim. Prepending the shim directory to your PATH ensures that go, gofmt, and other Go toolchain commands resolve through govm's wrappers.

Using the TUI

Run govm with no arguments to launch the interactive terminal UI:

govm

The TUI presents two views you can toggle with Tab:

  • Available Versions: all Go releases fetched from go.dev
  • Installed Versions: releases you have already installed locally
Key Action
/ Move up or down the list
Tab Switch between Available and Installed views
i Install the selected version
u Switch to the selected version
r Refresh the list from go.dev
q Quit

The TUI is particularly useful when you want to browse available releases or visually confirm what is installed before switching.

Built on Charmbracelet

govm's TUI is powered by the Charmbracelet family of libraries: Bubbletea drives the interactive event loop, Bubbles provides ready-made UI components like lists and spinners, and Lipgloss handles the styling and layout. If you have ever wanted to build a polished TUI in Go, govm is a great project to read through for inspiration.

Using the CLI

For day-to-day use, the CLI subcommands are faster than opening the TUI.

Install a version

govm install 1.24

You can use a partial version number. govm resolves it to the latest patch release in that series, so 1.24 installs the latest 1.24.x available on go.dev.

To pin to a specific patch release, use the full version:

govm install 1.23.8

Switch to an installed version

govm use 1.23

After this command, go version reflects the switch immediately in any new shell (and in the current shell, since the shim resolves dynamically).

List installed versions

govm list

Show help

govm help

How the Shim Approach Works

govm uses a shim directory rather than symlinking or modifying your system Go installation directly. Here is what happens under the hood:

  1. Installation: govm downloads a Go release tarball from the official go.dev CDN and unpacks it to ~/.govm/versions/<version>.
  2. Shim creation: govm writes thin wrapper scripts to ~/.govm/shim for go, gofmt, and other Go toolchain binaries.
  3. Version switching: When you run govm use <version>, govm updates the wrappers to point at the target version directory. No PATH manipulation, no shell reload.
  4. Execution: When you run go build (or any other Go command), your shell finds the wrapper in ~/.govm/shim, which immediately delegates to the selected Go binary.

This design means the version change is instant and persistent across all terminals. You do not need to source anything or restart your shell after switching.

Partial version matching

When you specify 1.24 instead of 1.24.3, govm selects the latest installed patch in that minor series. If you have 1.24.2 and 1.24.3 installed, govm use 1.24 activates 1.24.3. This keeps commands short while still being deterministic.

Practical Workflow for Open Source Contributors

Here is how this plays out in practice when contributing to projects with different Go requirements.

Checking the required Go version

Most Go projects declare their minimum version in go.mod:

module github.com/example/project

go 1.23

Some also pin CI to a specific release in their workflow:

- name: Setup Go
  uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
  with:
    go-version: '1.23.8'

Switching to match the project

Once you know the required version, switching is a single command:

govm use 1.23

Confirm the active version:

go version
# go version go1.23.8 linux/amd64

Keeping up with new releases

When a new Go release ships, install it without removing the previous one:

govm install 1.24
govm use 1.24

Your older installations remain in ~/.govm/versions and are available at any time:

govm use 1.22
go version
# go version go1.22.13 linux/amd64

Summary

govm does one thing well: it gets out of your way when you need to switch Go versions. The shim-based design avoids the shell-reload ceremony that other version managers require, and the TUI makes browsing available releases pleasant rather than a trip to a downloads page.

If you work across multiple Go projects or like to test your code against more than one release, govm is worth adding to your toolbox.

Task Command
Install a version govm install 1.24
Switch to a version govm use 1.24
List installed versions govm list
Launch the TUI govm

You can find the project, report issues, and contribute at github.com/melkeydev/govm.