Go 1.26's go fix got a lot better - now an automatic code modernization tool
Contents
In Go 1.26, the go fix subcommand was rewritten from scratch. It is no longer just a code-fixing tool; it has become a “modernizer” that automatically converts Go codebases to the latest idioms. Go’s official blog published a detailed write-up.
Basic usage
# Fix all packages under the current directory
go fix ./...
# Preview the changes without modifying files
go fix -diff ./...
# List available fixers
go tool fix help
Main fixers
Converting interface{} to any
Use the any alias introduced in Go 1.18 to replace older interface{} declarations in bulk.
// Before
func foo(x interface{}) {}
// After
func foo(x any) {}
Using the built-in min/max
Convert manual if-based clamping logic to the built-in min/max functions added in Go 1.21.
// Before
x := f()
if x < 0 { x = 0 }
if x > 100 { x = 100 }
// After
x := min(max(f(), 0), 100)
rangeint - Go 1.22’s integer range loop
Convert loops that do not need a counter variable to the integer range syntax introduced in Go 1.22.
// Before
for i := 0; i < n; i++ { f() }
// After
for range n { f() }
new(expr) - the new Go 1.26 syntax
This is the headline feature of Go 1.26. Previously, new() only accepted types; now it can take values directly.
// Before - common helper-function pattern
func newInt(x int) *int { return &x }
data, _ := json.Marshal(&Request{Attempts: newInt(10)})
// After - the helper is no longer needed
data, _ := json.Marshal(&Request{Attempts: new(10)})
Running go fix -newexpr ./... automatically finds helpers like newInt, rewrites them to return new(x), and updates call sites to use new(expr) directly. Helpers such as proto.Int64 and proto.String are also no longer needed.
Other fixers
stringscut: convertsstrings.IndexBytepatterns tostrings.Cutforvar: removes loop-variable shadowing that is no longer needed since Go 1.22fmtappendf: converts[]byte(fmt.Sprintf(...))tofmt.Appendfstringsbuilder: replaces string concatenation in loops withstrings.Builder
Synergy effects
Running multiple fixers in sequence can yield additional improvements. The write-up says it usually reaches a fixed point after two runs.
Performance improvements
There are major internal improvements too. In the typeindex-based precomputation of function-call indexes, one example reported a 1000x speedup.
The new(expr) conversion alone is big because it can wipe out a lot of newInt-style helper functions. Once you move to Go 1.26, the first thing to do is probably go fix ./....