If you haven't tried the new "go fix" yet, give it a spin.
It's a proper revival of the old "gofix" idea. In Go 1.26, it was rebuilt on top of the Go analysis framework. So now it can modernize your code with newer language and stdlib features.
It respects the Go version in your module. If your "go.mod" says "go 1.26", it suggests Go 1.26-compatible changes. It doesn't rewrite your code into something your module hasn't opted into.
For teams using LLMs, this is great. You don't need to keep leaving PR comments like “use the newer API here” or “we don't write that pattern anymore.” Run it locally or on the CI instead.
Start from a clean git state:
go fix -diff ./...
Then apply it:
go fix ./...
Then run it again.
Some fixes expose more fixes. The Go team recommends rerunning it, and in practice two passes often catches more than one.
Some useful analyzers:
-
-
-
-
-
... and many more
You can also run one analyzer at a time if you want smaller PRs:
go fix -newexpr ./... go fix -forvar ./...
That's useful when one pass touches a lot of files and you don't want one giant mixed cleanup patch.
The other neat bit is . Library authors can use it to help users migrate from old APIs to new APIs. That's much better than deprecating something and hoping everyone reads the changelog.
You can also write your custom analyzer to enforce your own rules. I am writing a few for fun.
The Go blog has two good posts on it:
I ran it on a large RPC service, and "newexpr" cleaned up a pile of pointer helper calls. Extremely satisfying.