Modernizing Your Go Codebase with go fix: A Step-by-Step Guide
Overview
Keeping your Go code up to date with the latest language features and standard library improvements not only makes your code cleaner and more idiomatic but can also improve performance and readability. The go fix command, introduced in its rewritten form with Go 1.26, provides an automated way to identify and apply these modernizations across your entire codebase. Instead of manually hunting for outdated patterns, go fix runs a suite of analysis tools (called fixers) that detect opportunities for improvement and apply the changes for you. This tutorial will guide you through using go fix effectively, from basic usage to advanced tips, so you can confidently modernize your Go projects with every toolchain upgrade.
Prerequisites
Before diving into go fix, ensure you have the following:
- Go 1.26 or later – The rewritten
go fixis available starting with this version. Rungo versionto verify. - A Go project – Any codebase you want to modernize. It's best to start with a clean Git state (no uncommitted changes) so you can easily review and revert the automated edits.
- Familiarity with the command line – You'll run commands in a terminal.
Step-by-Step Instructions
1. Running go fix on Your Project
The simplest way to apply all available fixers to your project is to run:
$ go fix ./...This command processes all packages under the current directory (use ./... recursively). On success, go fix silently updates your source files in place. If any fixer encounters a generated file (e.g., files marked with // Code generated ...), it skips that file because the correct fix belongs in the generator itself, not the output. For best results, run go fix each time you upgrade your Go toolchain to a new release.
2. Previewing Changes with the -diff Flag
Before committing automated edits, always preview them. Use the -diff flag to see a unified diff of what would change:
$ go fix -diff ./...Example output:
--- dir/file.go (old)
+++ dir/file.go (new)
- eq := strings.IndexByte(pair, '=')
- result[pair[:eq]] = pair[1+eq:]
+ before, after, _ := strings.Cut(pair, "=")
+ result[before] = afterThe diff shows exactly which lines are replaced. This is invaluable for code review and for understanding what each fixer does.
3. Listing Available Fixers
To see the complete list of fixers registered in your Go toolchain, run:
$ go tool fix helpYou'll see output like:
Registered analyzers:
any replace interface{} with any
buildtag check //go:build and // +build directives
fmtappendf replace []byte(fmt.Sprintf) with fmt.Appendf
forvar remove redundant re-declaration of loop variables
hostport check format of addresses passed to net.Dial
inline apply fixes based on 'go:fix inline' comment directives
mapsloop replace explicit loops over maps with calls to maps package
minmax replace if/else statements with calls to min or max
...Each analyzer has a name and a brief description. To get detailed documentation for a specific analyzer, use:
$ go tool fix help <fixer-name>For example:
$ go tool fix help forvar
forvar: remove redundant re-declaration of loop variables
The forvar analyzer removes unnecessary shadowing of loop variables.
Before Go 1.22, it was common to ...4. Running Specific Fixers
Sometimes you only want to apply a particular fix. You can pass a comma-separated list of fixer names with the -fix flag:
$ go fix -fix=any,minmax ./...This runs only the any and minmax analyzers. It's useful for incremental modernization or when you want to focus on one category of improvements at a time.

5. Integrating with Your Workflow
To make go fix a regular part of your development cycle, consider adding it to your CI pipeline or pre-commit hooks. For example, after upgrading Go in a CI job, run go fix ./... and fail the build if changes are detected (using git diff --exit-code). Alternatively, run go fix -diff ./... and only apply changes after manual review. The key is to run it from a clean Git state so the commit history clearly reflects only the fixer's modifications.
Common Mistakes
Ignoring the -diff Preview
The biggest mistake is trusting go fix blindly without reviewing its changes. While the tool is safe, it's always wise to inspect diffs before committing. Automated fixes might introduce subtle issues or change code style in ways you didn't expect. Always run go fix -diff first.
Running Without a Clean Git State
If you have uncommitted changes, go fix will mix its edits with yours, making it hard to differentiate what was automated. Start from a clean working tree (e.g., git stash or commit your changes) so that the diff shows only go fix modifications.
Applying Fixes to Generated Files
go fix automatically skips generated files, but if you force it or modify the generator, you might accidentally edit generated code. Always fix the generator logic instead. If you see a fix being skipped on a generated file, take that as a hint to update the generator.
Not Updating Go Toolchain First
The fixers in go fix are tied to the Go version you're using. If you run an older toolchain, you won't get the latest analyzers. Always upgrade to the latest release before running go fix to get the most comprehensive modernization.
Running go fix Without Specific Fixers
By default go fix runs all registered fixers. If you want to avoid certain changes (e.g., replacing interface{} with any), you must explicitly exclude those fixers. Currently go fix doesn't support a blacklist, but you can run only the fixers you want with -fix=list.of.fixers.
Summary
go fix is a powerful tool for automatically modernizing your Go code to use newer language features and improved APIs. By running it after each Go toolchain upgrade, you ensure your codebase stays idiomatic and streamlined. The key steps are: start from a clean Git state, preview changes with -diff, understand available fixers via go tool fix help, and apply selectively when needed. Avoid common pitfalls like skipping previews or editing generated files. Incorporate go fix into your regular maintenance workflow to keep your Go projects clean, efficient, and up to date.