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:
- Download the new tarball from go.dev/dl.
- Unpack it somewhere.
- Update your
$PATHto point to the new Go bin directory. - Reload your shell.
- 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:
After installation, run govm to launch the TUI.
Using Homebrew (macOS and Linux)¶
If you prefer Homebrew, add the tap and install:
From Source¶
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:
For Bash users, replace ~/.zshrc with ~/.bash_profile or ~/.bashrc.
Add the shim directory to your shell configuration:
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:
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
Navigation¶
| 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¶
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:
Switch to an installed version¶
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¶
Show 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:
- Installation: govm downloads a Go release tarball from the official go.dev CDN and unpacks it to
~/.govm/versions/<version>. - Shim creation: govm writes thin wrapper scripts to
~/.govm/shimforgo,gofmt, and other Go toolchain binaries. - Version switching: When you run
govm use <version>, govm updates the wrappers to point at the target version directory. NoPATHmanipulation, no shell reload. - 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:
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:
Confirm the active version:
Keeping up with new releases¶
When a new Go release ships, install it without removing the previous one:
Your older installations remain in ~/.govm/versions and are available at any time:
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.