Tech 2 min read

Go 1.26's go fix got a lot better - now an automatic code modernization tool

IkesanContents

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: converts strings.IndexByte patterns to strings.Cut
  • forvar: removes loop-variable shadowing that is no longer needed since Go 1.22
  • fmtappendf: converts []byte(fmt.Sprintf(...)) to fmt.Appendf
  • stringsbuilder: replaces string concatenation in loops with strings.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 ./....

Using go fix to modernize Go code - The Go Blog