Skip to content

`govm`: Switch Between Go Versions Without the Headache

If you write Go code regularly across multiple projects, you've almost certainly hit this: 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 handles it for you.

govm is a lightweight, open-source Go version manager built by Melkey. It ships both a terminal UI (TUI) and a 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. I jump between Go releases a lot for open source work, and it's become a regular part of my setup.

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're working across many repositories with different Go requirements, it gets old fast.

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've 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 handy when you want to browse available releases or see what's 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've ever wanted to build a TUI in Go, govm is a good codebase to read.

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's 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 don't 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's 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.