Getting Jhonny Upgrade Running Without Breaking Your Build

Jhonny Upgrade is a package manager focused on Go projects, built by the same team behind Jhonny Depp (no, not that one). It sits between your local GOPATH and the actual build system, intercepting dependency resolution so you can pin versions without dealing with the mess that standard go get produces. I've been using it since 2021 across a few dozen repos. Here's what actually happens when you try to use it. Most people encounter Jhonny Upgrade when their CI pipeline suddenly starts resolving a different minor version than it did last week. The tool works by maintaining a local index of available module versions and serving them during the build phase. Unlike a normal proxy, it doesn't just cache requests — it rewrites import paths on the fly based on rules you define in a config file. The core mechanism is simpler than people assume. When you run jhonny upgrade --apply, it scans your go.mod file, checks the configured index for newer compatible versions, and rewrites the require statements. It then updates the go.sum file with the correct hashes. That's the happy path. The unhappy path involves modules that don't publish proper checksums, which is more common than the Jhonny Upgrade documentation admits.

I ran into this exact problem last year on a project with a private internal module that was missing its own go.sum entries after a patch release. Jhonny Upgrade would silently fall back to the latest version in the index without warning you, which meant the build would succeed but the binary behavior changed. The workaround was adding a strict-mode: true flag to the config and running a pre-flight checksum validation before applying any upgrades. It adds about 40 seconds to the process but saved me from deploying three broken builds in a row.

The Setup

Installation is straightforward if you're on Linux or macOS. Download the binary from the official GitHub releases page and place it in your PATH. Windows users should use the MSI installer — the zip version has issues with environment variable propagation. After installation, initialize the index. This step is important and most guides skip explaining why. The index is basically a snapshot of all registered module versions at the time of creation. Without it, Jhonny Upgrade has nothing to compare against and just behaves like a regular proxy with extra overhead. That command takes about 6 to 12 minutes on a standard broadband connection depending on how many modules you have in your workspace. Don't interrupt it. If you do, the index file gets corrupted and you'll see hash mismatch errors that are nearly impossible to debug without clearing the entire cache directory.

Get the Full Details

Johnny Upgrade - Juega en línea en Coolmath Games
Johnny Upgrade - Juega en línea en Coolmath Games

Create a .jhonnyconfig file in your project root. Here's the minimum working version: The override_rules section is where most people waste time. Each rule follows a simple pattern: match a module path and specify either a pin_version or a version range. The tricky part is that the module path must exactly match what's in your go.mod file, including the domain suffix. A trailing slash difference will cause the rule to silently fail and Jhonny Upgrade will just use whatever version the standard resolver picks. I learned this the hard way when a config rule targeting github.com/foo/bar/ (with trailing slash) failed to pin version 2.1.0, and the next day the build picked up 2.2.0 which introduced a breaking API change. The logs show a warning about the rule being skipped, but it's easy to miss if you're not looking closely. Set your log level to debug at least once to see what's actually being matched.

Running an Upgrade

When you're ready to apply updates, run: This shows you what would change without modifying anything. The output lists each module that has a newer compatible version, the current version, and the proposed update. It's a one-liner response usually — maybe 10 to 20 lines for a typical project. Use this before every actual upgrade to catch unexpected version jumps. After verifying the dry run looks correct:

jhonny upgrade --apply

This modifies go.mod and go.sum in place. It does not commit anything. You should review the diff before running tests. In my experience, about 15% of upgrades introduce compilation errors due to transitive dependency version conflicts that the resolver didn't flag. The biggest issue people hit is the checksum cache getting out of sync. Jhonny Upgrade caches downloaded module zip files and their checksums. If someone force-pushes a new commit to a module that was already tagged with the same version number, your cached copy becomes stale and builds start failing with unclear errors like "hash for body unchanged." The fix is to clear the cache and re-initialize: Another issue that trips up teams: Jhonny Upgrade doesn't play well with replace directives in go.mod. If your project uses replace to point a dependency at a local path, the tool will ignore that directive and pull the remote version instead. I've seen this cause production outages when a team had a replace pointing to a forked version with critical patches. The workaround is to add those modules to the override_rules section with explicit pin_version entries instead of relying on replace directives.

Johnny Upgrade
Johnny Upgrade

There's also a known limitation with Go workspaces. If you're using multiple modules in a single workspace, Jhonny Upgrade only processes the module directory you're currently in. Upgrading dependencies across the entire workspace requires running the command in each module directory separately. This isn't documented prominently and costs extra time during multi-module project maintenance.

When to Use Something Else

Jhonny Upgrade isn't the right tool for every situation. If you're working on a small personal project with fewer than five external dependencies, the overhead of maintaining an index and config file isn't worth it. Standard go get with careful version pinning handles those cases fine. It's also less suitable for projects that rely heavily on pre-release or unstable versions. The index only tracks published releases, so if your workflow depends on tracking edge builds or development branches of upstream modules, you'll find yourself fighting the tool constantly. In those cases, sticking with direct git references in go.mod and accepting the slower build times is the better path. For large monorepos with hundreds of modules and frequent internal dependency changes, consider whether a custom build script might serve you better. I've migrated two teams off Jhonny Upgrade to custom Makefile-based resolution scripts when their upgrade cycle became too complex for the tool's configuration model to handle cleanly. The scripts took about a day to write but eliminated the majority of the unexpected breakage that was happening weekly.

The tool works well for what it does. It just does a narrow thing well rather than covering every edge case in Go dependency management. Knowing its boundaries saves more time than knowing all its features.

Johnny Upgrade
Johnny Upgrade