Modernize Your Go Code with go fix: A Q&A Guide

By ● min read
<p>The <strong>go fix</strong> command, revamped in Go 1.26, is a powerful tool for automatically modernizing your Go codebase. It applies a suite of analyzers that identify outdated patterns and replace them with more idiomatic, efficient, and modern equivalents—saving you hours of manual refactoring. This Q&A covers everything from running the command to understanding its internal machinery and extending it for your own guidelines.</p> <h2 id="what">What exactly does <code>go fix</code> do for my code?</h2> <p><code>go fix</code> scans your Go source files and applies a series of built-in analyzers to detect opportunities for improvement. For example, it can replace <code>interface{}</code> with <code>any</code>, convert explicit loop iterations over maps to calls to the <code>maps</code> package, or replace <code>if/else</code> patterns with <code>min</code> and <code>max</code> functions. Each fixer is designed to take advantage of modern language features or libraries introduced in recent Go releases. The command runs silently on success, updating files in place while skipping generated code (since that should be fixed at the generator level). Running it after upgrading to a newer Go toolchain is highly recommended to keep your codebase aligned with current best practices.</p><figure style="margin:20px 0"><img src="gofix-analysis-facts.svg" alt="Modernize Your Go Code with go fix: A Q&amp;A Guide" style="width:100%;height:auto;border-radius:8px" loading="lazy"><figcaption style="font-size:12px;color:#666;margin-top:5px">Source: blog.golang.org</figcaption></figure> <h2 id="run">How do I run <code>go fix</code> on my project?</h2> <p>The command follows the same pattern as <code>go build</code> or <code>go vet</code>. To fix all packages beneath the current directory, simply run:</p> <pre><code>$ go fix ./...</code></pre> <p>This updates your source files directly, so it's wise to start from a clean Git state—that way your commit contains only the changes made by <code>go fix</code>, making code review straightforward. If you prefer to examine changes before applying them, use the <code>-diff</code> flag as described in <a href="#preview">the next question</a>. The command handles all packages in the given patterns, and it will skip any file it considers generated (based on the usual Go conventions).</p> <h2 id="preview">Can I preview what <code>go fix</code> will change without applying it?</h2> <p>Absolutely. Use the <code>-diff</code> flag to see a unified diff of the proposed changes:</p> <pre><code>$ go fix -diff ./...</code></pre> <p>This prints the diff to the terminal without modifying any files. For example, it might show:</p> <pre><code>--- dir/file.go (old) +++ dir/file.go (new) - eq := strings.IndexByte(pair, '=') - result[pair[:eq]] = pair[1+eq:] + before, after, _ := strings.Cut(pair, &quot;=&quot;) + result[before] = after</code></pre> <p>This is especially useful when you want to review each fix before committing, or when integrating <code>go fix</code> into a CI pipeline to check for potential issues without altering the codebase.</p> <h2 id="list-fixers">How do I see which fixers are available and get details about them?</h2> <p>To list all registered analyzers (fixers), run:</p> <pre><code>$ go tool fix help</code></pre> <p>This outputs a list like:</p> <pre><code>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 ...</code></pre> <p>For complete documentation of a specific analyzer, add its name to the help command, for instance:</p><figure style="margin:20px 0"><img src="https://go.dev/images/google-white.png" alt="Modernize Your Go Code with go fix: A Q&amp;A Guide" style="width:100%;height:auto;border-radius:8px" loading="lazy"><figcaption style="font-size:12px;color:#666;margin-top:5px">Source: blog.golang.org</figcaption></figure> <pre><code>$ go tool fix help forvar</code></pre> <p>This shows a detailed description, including the problem it solves and the transformation it applies.</p> <h2 id="modernization-examples">What are some real-world examples of code modernization with <code>go fix</code>?</h2> <p><code>go fix</code> tackles a variety of outdated patterns. One common fix is replacing <code>interface{}</code> with the shorthand <code>any</code> (available since Go 1.18). Another converts manual string splitting using <code>strings.IndexByte</code> and slicing to the cleaner <code>strings.Cut</code> call. The <code>forvar</code> analyzer removes unnecessary shadowing of loop variables, a pattern that was common before Go 1.22 introduced per-iteration variables. The <code>mapsloop</code> fixer replaces explicit <code>for k, v := range m { ... }</code> patterns with calls to <code>maps.Keys</code>, <code>maps.Values</code>, or <code>maps.Clone</code> when appropriate. Each fixer is designed to produce more maintainable and idiomatic Go without changing the program's behavior.</p> <h2 id="when-run">When should I run <code>go fix</code> and what are the best practices?</h2> <p>The official recommendation is to run <code>go fix ./...</code> every time you upgrade to a newer Go toolchain release. This ensures your code stays up-to-date with language improvements and library deprecations. Always commit or stash your current changes first so that the diff contains only the automatic fixes. If you're working in a team, integrate <code>go fix</code> into your CI pipeline to catch outdated patterns early. For modules that use generated code, remember that <code>go fix</code> automatically skips generated files; any necessary fixes there should be applied to the generator itself. Finally, use the <code>-diff</code> flag during code review to show reviewers exactly what changed.</p> <h2 id="evolution">How is <code>go fix</code> evolving and can I create my own fixers?</h2> <p>The Go team has rearchitected <code>go fix</code> to be more extensible. Beyond the built-in analyzers, there is a growing theme of <em>self-service</em> analysis tools. Module maintainers and organizations can encode their own guidelines and best practices into custom analyzers that <code>go fix</code> can then apply. While the current release focuses on built-in fixes, the infrastructure supports future customization. This means you could develop internal fixers for code style rules, migration patterns, or API deprecations specific to your project. The command's modular design also makes it easier to add new analyzers over time, ensuring <code>go fix</code> remains a valuable tool for keeping Go codebases modern.</p>
Tags: