Go 1.22: Updates That Simplify Idiomatic Code
Actualizado: 2026-05-03
Go 1.22 shipped on February 6, 2024, and fixes two frictions that have shaped the language experience for almost a decade: loop variable semantics and the poverty of the standard HTTP router. Add to that a mature toolchain system and a handful of targeted standard library improvements. No single novelty reinvents Go, but the net result is that idiomatic 2024 code is written with fewer traps and fewer external dependencies.
Key takeaways
- The loop-capture fix is the most impactful change: from 1.22,
forvariables are re-declared each iteration whengo.moddeclaresgo 1.22. The defensivex := xdisappears. net/http.ServeMuxnow supports method as pattern prefix, named segments, and wildcard — making gorilla/mux or chi unnecessary for simple projects.for i := range 10is the visible syntactic sugar; it aligns writing with the range style that already dominates the idiom.- Managed toolchain (
toolchainingo.mod) resolves the logistical friction of teams with different installed versions. math/rand/v2with ChaCha8 inaugurates the/v2scheme inside the stdlib, the first intentional compatibility break.
The End of the Loop-Capture Trap
Until 1.21, variables declared in a for header shared their address across iterations. Any closure or goroutine spawned inside the loop captured the same variable rather than its value at that instant.
From 1.22 onward, if go.mod declares go 1.22, the variable is re-declared each iteration. The proposal was exercised throughout the 1.21 cycle behind GOEXPERIMENT=loopvar, and the Go team published an audit of Google’s codebase confirming the change fixed real bugs and broke almost nothing.
This is the kind of fix that justifies an entire release. It doesn’t change how new code is written, but it erases a whole class of latent bugs in older code.
ServeMux Learns to Route
In 1.22 the standard multiplexer accepts the method as a pattern prefix, named segments in braces, and a {rest...} wildcard:
mux := http.NewServeMux()
mux.HandleFunc("GET /users/{id}", getUser)
mux.HandleFunc("POST /users", createUser)
mux.HandleFunc("DELETE /users/{id}", deleteUser)
func getUser(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
// use the captured id
}For a small-to-medium REST service, this makes an external router unnecessary. Frameworks still bring value when there’s shared middleware, automatic validation, or OpenAPI generation, but the entry step for serving a clean API without dependencies has dropped noticeably.
Range Over Integers and Other Language Touches
for i := range 10 lets you write a numeric loop without the classic i := 0; i < n; i++. It aligns the writing with the range style that already dominates the language. It’s the kind of change that feels natural in six months and is forgotten as ever-different in twelve.
Toolchain: Module Version and Compiler Version
gomarks the minimum language version the module assumes.toolchainindicates which specific compiler version should be used.- If the declared toolchain isn’t installed,
godownloads it transparently.
For teams where machines with different installed versions coexist, or for CI that isn’t always up to date, this solves a logistical problem previously handled with hand-written scripts or asdf.
The Periphery of the Standard Library
Three changes deserve attention:
math/rand/v2debuts the ChaCha8 generator and a cleaner API while keepingmath/randintact. First package to inaugurate the/v2scheme inside the stdlib.log/slog, stabilised in 1.21, consolidates as the natural replacement forlogfor structured logging without zap or zerolog.govulncheckkeeps maturing as the official vulnerability-checking tool. Reasonable to wire into CI now.
What Can Break on Migration
The loop semantics change needs the most attention, though tests usually catch it. ioutil is fully deprecated; migration to os and io is mechanical and gopls suggests it. For most repositories, the update is: install 1.22 toolchain, flip go directive in go.mod, run go vet ./... and tests. An afternoon is enough outside pathological cases.
Conclusion
Go 1.22 confirms the language’s deep thesis: progress arrives slowly, goes through long proofing processes, and respects backwards compatibility almost religiously. The loop-capture fix genuinely changes how concurrent Go is written. The ServeMux with methods and parameters changes the decision of which router to use on new projects. Managed toolchains change how someone new is onboarded. Updating doesn’t hand out spectacular performance or dazzling syntax, but it does pull two stones out of the shoe that had been there far too long.