CLI tool
oligot/go-mod-upgrade avatar
oligot/go-mod-upgrade

go-mod-upgrade: the interactive dependency upgrade the Go wiki leaves to a shell script

Update outdated Go dependencies interactively

1,110 stars53 forksGoMIT

At a glance

What is it?
go-mod-upgrade is an MIT-licensed Go tool that shows available dependency upgrades and lets you pick them one at a time, with a cooldown window, colour-coded update types and a non-interactive list mode. The judgement is that the cooldown and the list mode are what make it CI-usable, and that the tool deliberately leaves the actual upgrade to the Go toolchain rather than doing it itself.
Who is it for?
go-mod-upgrade fits a Go developer with a module-based project who has dozens of outdated direct dependencies and wants to review each upgrade rather than apply them in bulk, and who wants a policy that skips releases published in the last few days. It does not fit a project whose dependencies are managed by a lockfile-driven tool or vendored, and it does not fit a team that wants a tool to perform the upgrade as well as list it.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 5 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The Go wiki's command shows upgrades but cannot act on them

go-mod-upgrade is a small Go tool for updating outdated dependencies interactively, and its reason for existing is a gap in the standard workflow.

The project starts from the Go wiki's section on How to Upgrade and Downgrade Dependencies, and quotes the command the wiki suggests:

bash
go list -u -f '{{if (and (not (or .Main .Indirect)) .Update)}}{{.Path}}: {{.Version}} -> {{.Update.Version}}{{end}}' -m all 2> /dev/null

That gives you a list of available upgrades for direct dependencies. The problem the README identifies is that the output is not actionable, meaning you cannot easily use it to update multiple dependencies.

That is the whole pitch. The tool is described as an attempt to make it easier to update multiple dependencies interactively, and the comparison the documentation draws is with `yarn upgrade-interactive`, but for Go.

The comparison is informative because it fixes the mental model. You are not being handed a bulk update command. You are being handed a list with a selection, one module at a time, where you decide which to take. The difference from the wiki command is the decision, not the automation.

Major version updates are supported by default via the pkg.go.dev API, which is worth noting because Go's own tooling historically treated major version changes as something you had to opt into deliberately. Here they are on by default, and there is a flag to turn them off.

The implementation is Go, with the module path `github.com/oligot/go-mod-upgrade` and the licence MIT. The dependency list shows a terminal UI stack built on Bubble Tea and Bubbles from the charm library set, a `huh` form component, and lipgloss for styling, plus `Masterminds/semver` for version comparison and `golang.org/x/mod` for module handling.

Colour tells you the risk of each row before you pick it

The interactive mode shows available module upgrades with colour coding, and the colour is not decoration. It encodes the semver category of the update, which is the information you need before deciding.

Magenta is a major update, yellow is a minor update, green is a patch update, and red is a prerelease update.

That mapping is what makes the tool usable at a glance. A green row is safe to take in most projects, a yellow row might change behaviour, a magenta row is a breaking change that will need code work, and a red row is a prerelease that most projects should not adopt by accident. The tool does not make the decision for you, it just puts the decision's shape in front of you.

There is a second colour distinction, in the output format rather than the type. When the latest version falls inside the cooldown window, go-mod-upgrade offers the greatest version that is old enough instead, and annotates the row with the version it withheld:

code
github.com/foo/bar  1.2.0 -> 1.3.0  (1.4.0 held, 2d old)

So the row tells you both what you would get and what you are not getting, which is the difference between a policy you can respect and one you can only hope is applied.

If no version satisfies the window, the module is held back entirely and reported after discovery:

code
1 module held back by cooldown (7d):
  github.com/only/new 1.0.1 (1d old)

And the `--list` flag gives you the same information without any interactivity, using the same colour coding, which the documentation says makes it perfect for CI/CD pipelines or for just checking what is available.

Cooldown is a settling policy, and the documentation is honest about its limit

The `--cooldown` flag exists to avoid adopting a version the moment it is released, and it requires a version to have been published for a given period.

bash
go-mod-upgrade --cooldown 7d

The accepted values follow the npm-check-updates convention, and the table in the documentation gives the meanings: `7` is 7 days, `7d` is 7 days, `12h` is 12 hours, and `30m` is 30 minutes.

What is unusual is the caveat that comes with it, and it is a good one. Go reports the VCS tag time of a version, not a server-side publish time as npm does, so someone in control of a repository could backdate a tag. Treat cooldown as a way to let a release settle before adopting it, rather than as a hard guarantee against a compromised release.

That is a materially different guarantee from the one the npm equivalent gives you, and the project says so rather than leaving you to assume parity. A tag time is under the control of whoever pushed the tag, whereas an npm publish time is under the control of the registry. For most workflows the difference does not matter, because the purpose of a cooldown is to avoid adopting a version in the window where a broken release is most likely to be discovered and yanked or patched. But if your threat model includes a hostile dependency maintainer, the flag reduces exposure rather than removing it.

The other thing to note is that the cooldown interacts with the major version lookup rather than replacing it. It only considers versions published at least this long ago, and it applies while checking for major version updates, which is the operation that needs the extra network round trip and the disk cache.

The global options are where the CI use case lives

The full set of global options is listed in the documentation, and several of them exist for automation rather than for interactive use.

`--list`, `-l` lists available module upgrades without interactivity, which is the flag you would use in a pipeline to report what is available.

`--force`, `-f` forces an update of all modules in non-interactive mode, which is the flag for the case where you have decided, by policy or by review elsewhere, that everything should move.

`--no-major` disables checking for major version updates, and `--no-cache` skips the disk cache when checking for major version updates. Those two are related. Major version lookups need to consult the pkg.go.dev API, and the result is cached on disk, so the cache is what makes repeated runs cheap. Turning the cache off is a way to force a fresh check.

`--ignore`, `-i` takes a regular expression and ignores modules matching it, which is how you pin a specific dependency out of a bulk run without vendoring it.

`--hook` takes a command to execute for each updated module. That is the extension point for a project that needs to do something after a module is bumped, for instance run a code generator or update a checksum file, and it is worth noting that the hook runs per updated module rather than once at the end.

The remaining options are ordinary. `--pagesize`, `-p` sets the page size for the interactive list, defaulting to 10. `--verbose`, `-v` turns on verbose mode. `--help` and `--version` do what you would expect.

The structure of the option set tells you what the tool is for. There is a flag to list, a flag to force, a flag to ignore, a flag to hook, and a flag to hold back fresh releases. Every one of them is about controlling the set of upgrades that get applied, which is a different design from a tool that just runs `go get -u ./...` and hopes for the best.

Installing it is a binary download or a go install

There are two installation routes, and they are both short.

Pre-compiled binaries for Windows, OS X and Linux are available in the releases page, which is the route for a CI image or a machine without a Go toolchain.

With the Go toolchain installed, the alternative is:

bash
go install github.com/oligot/go-mod-upgrade@latest

The `main.go` file at the repository root and the `internal/` directory hold the implementation, with `testdata/` for test fixtures, and there is a `mise.toml` and `mise.lock` for toolchain pinning, which suggests the maintainer develops against a specific Go version rather than whatever is on the path.

The build itself is handled by a `.goreleaser.yml`, and the module path in `go.mod` declares `go 1.26.6`, so the tool needs a current Go toolchain to build from source.

The `go.mod` also shows the CLI is built on `urfave/cli/v3`, and the `charm.land/huh/v2` dependency is the interactive form component, with Bubbles providing the list and spinner widgets and `bubbletea` the runtime that drives them. `Masterminds/semver` does the version comparison that the colour coding depends on, and `github.com/apex/log` and `github.com/fatih/color` handle logging and the terminal colours.

The repository also has a `CLAUDE.md` at the root and a `readme.md` in lowercase, which is a small inconsistency worth noting only because the file names differ from the more common `README.md` and `LICENSE` convention. The licence file here is `License`, without an extension.

The tool selects upgrades, the Go toolchain performs them

There is a scope boundary here that the documentation does not belabour but that matters for what you should expect.

go-mod-upgrade is a selection and reporting tool. It determines which modules have available upgrades, presents them for a decision, and applies the ones you pick. The dependency list is telling here: `golang.org/x/mod` is there, and that is the module that provides the `golang.org/x/mod/modfile` and `golang.org/x/mod/semver` packages used to read and edit `go.mod`. So the tool is operating on the `go.mod` file and the module graph, and the resulting change is expressed in the module file, which is then resolved by the Go toolchain in the normal way.

What this means in practice is that after an upgrade you still have the ordinary Go workflow: the `go.mod` file changes, `go.sum` changes, and you build and test as usual. The tool does not vendor, does not patch your source, and does not try to fix compilation errors that a major version upgrade introduces. A magenta row that you accept is a promise to go and deal with the consequences yourself.

That boundary is the right design for the tool's purpose. The alternative would be a tool that also edited your code, and code migration across major versions is not something a general-purpose CLI should attempt.

The integration section lists one external tool that pairs with it, a Dev Container Feature for go-mod-upgrade, which brings the tool into a development container image so a team gets the same upgrade workflow regardless of what is on the host machine.

For the changelog, the documentation points at `CHANGELOG.md` in the repository. The release history in the repository shows v0.12.0 on 2025-09-23, then two betas for 0.13.0 in May 2026, v0.13.0-beta.0 on 2026-05-25 and v0.13.0-beta.1 on 2026-05-27. The last push was on 2026-09-13, and the repository is not archived, so the code is being worked on.

Editorial conclusion

go-mod-upgrade fits a Go developer with a module-based project who has dozens of outdated direct dependencies and wants to review each upgrade rather than apply them in bulk, and who wants a policy that skips releases published in the last few days. It does not fit a project whose dependencies are managed by a lockfile-driven tool or vendored, and it does not fit a team that wants a tool to perform the upgrade as well as list it. Verify first that the module proxy you use exposes the version metadata the tool reads, that the cooldown value you pick is expressed in the units you intend, since the accepted forms are days, hours and minutes, and that the `--hook` mechanism you rely on is a command you control, since it runs for each updated module.

Frequently asked questions

How do I install go-mod-upgrade?

Pre-compiled binaries for Windows, OS X and Linux are available in the releases page, or with the Go toolchain you can run `go install github.com/oligot/go-mod-upgrade@latest`. The module requires Go 1.26.6 to build from source.

What do the colours in the go-mod-upgrade list mean?

Magenta marks a major update, yellow a minor update, green a patch update and red a prerelease update. The colour tells you the semver category of the change before you choose to take it.

What does the --cooldown flag do in go-mod-upgrade?

It requires a version to have been published for a given period before it will be considered, accepting values such as `7`, `7d`, `12h` and `30m`. When the latest version falls inside the window, the tool offers the greatest version old enough and annotates the row with the version it withheld.

Can I use go-mod-upgrade in CI?

Yes, the `--list` flag displays all available module upgrades without interactivity, using the same colour coding, which the documentation says makes it suitable for CI/CD pipelines. The `--force` flag updates all modules in non-interactive mode, and `--hook` runs a command for each updated module.

Does go-mod-upgrade update the code for me when a major version breaks things?

No. The tool selects and applies the upgrade to the module files, and it operates on `go.mod` and the module graph using `golang.org/x/mod`. Code migration after a major version change is left to you, which is why major upgrades are colour coded separately.

Official sources

  1. Issues
  2. License: MIT
  3. oligot/go-mod-upgrade on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/oligot-go-mod-upgrade.svg)](https://hysenlabs.com/projects/oligot-go-mod-upgrade)

Was this useful?