Why This Article Covers Four Minor Versions at Once
Go releases happen every six months. Reading four sets of release notes in a row is not how anyone wants to spend an afternoon. But if you’re running Go in production, you need to know what’s changed.
This covers Go 1.22 through Go 1.26 — the versions that dropped between early 2024 and early 2026. That’s two years of language evolution in one place.
Go 1.22: The For Loop Changes Everything
February 2024. The most impactful change in Go 1.22 wasn’t a new package or a compiler optimization. It was the fix to how for loops handle variables.
Before Go 1.22, this code had a subtle bug:
var funcs []func()
for i := range 10 {
funcs = append(funcs, func() {
fmt.Println(i)
})
}
for _, f := range funcs {
f() // prints 9 ten times, not 0-9
}
Every closure captured the same variable i. By the time you called the functions, i was 9. This caught every Go developer at least once.
Go 1.22 changed this. Each loop iteration now creates new variables. The closures capture different variables. The code behaves as you’d expect — prints 0 through 9.
The Go team provided transition tooling so you could detect code that depended on the old behavior. go vet catches the pattern. But the fix itself was clean: if your code looked right, it probably was right.
Range over integers was the other notable addition:
for i := range 10 {
fmt.Println(10 - i)
}
Simple, obvious, eliminates a common pattern. for i := 0; i < n; i++ is not missed.
Go 1.26: The Self-Referential Generics Fix
February 2026. The latest stable release, and the change that matters most to anyone building generic data structures.
type Tree[T any] struct {
Value T
Left *Tree[T]
Right *Tree[T]
}
Before Go 1.26, this was illegal. A generic type couldn’t refer to itself in its type parameter list. You had to work around it with non-generic node types or interface tricks.
Go 1.26 lifted this restriction. Generic types can now refer to themselves, which means linked lists, trees, and graph nodes can be properly generic without wrapper types.
The new() builtin also got more flexible:
// Before: needed separate statement
n := new(int)
*n = 42
// After: expression form
n := new(int)
*n = new(42) // new can take an expression
The practical impact: working with optional fields in serialization (like encoding/json with pointer fields) becomes cleaner.
The Runtime Improvements Worth Knowing
Go 1.26 shipped a new garbage collector that reduces pause times by distinguishing between “must-collect” and “may-collect” work. The result: fewer stop-the-world pauses on latency-sensitive workloads.
Faster cgo calls landed in the same release. If you’re calling C from Go, the overhead dropped significantly. Not a change for everyone, but for the people who need it, it matters.
Heap base address randomization arrived as a security hardening measure. ASLR for Go heaps, making exploitation harder.
There’s also an experimental goroutine leak profiler. go tool trace can now identify where goroutines are leaking. If you’ve ever had a service that slowly accumulates goroutines until it falls over, this is the debugging tool you’ve been waiting for.
What Didn’t Change
Go’s philosophy stayed consistent across all four releases: maintain compatibility, improve the toolchain, avoid language complexity.
No significant syntax additions. No major paradigm shifts. The language is still small, still readable, still designed for teams.
This is either a feature or a limitation depending on what you’re comparing it to. Go doesn’t have the expressiveness of Rust’s traits or the polymorphism of Haskell’s type classes. But it also doesn’t have the cognitive overhead of understanding those features.
The Upgrade Math
Go 1.26 requires Go 1.22 or later to build. If you’re on an older version, you’re not getting security patches.
The for loop fix alone is worth upgrading for. The generics improvement matters if you write data structures. The GC improvements matter if you care about tail latency.
The cost: testing your code against the new version. The benefit: easier to reason about, fewer surprises, better performance.
For most teams, the math is simple. Stay current.
Next: practical Go project structure — how to organize a Go application that will still make sense in two years