Go 1.27 landed today (August 19, 2026), six months after 1.26. The headline is a language feature Go users have waited on for years, but the release notes reward a closer read. There's a generics change, a full post-quantum signature scheme wired into crypto/x509 and crypto/tls, and a major revision of encoding/json that mostly just makes your old code faster.
Generic methods, at last
The big one is that methods can now declare their own type parameters. Before, if you wanted a generic operation scoped to a particular type, you had to declare it at package scope. Now you can put it in the method's namespace.
math/rand/v2 is the showcase. Where 1.26 needed a separate method per integer type, 1.27 adds a single generic method:
func (r *Rand) N[Int intType](n Int) Intfunc (r *Rand) N[Int intType](n Int) IntOne method that works across all integer types, instead of three hand-written ones. The release notes note that interface methods still may not declare type parameters, nor can interface methods be implemented by generic methods. So this is expressive without loosening the interface rules.
Two smaller language changes ride along. A struct-literal key can now be any valid field selector, so you can initialize fields in nested or embedded structs directly:
type Gopher struct {
Name string
Habitat // embedded
}
g := Gopher{Name: "Gopher", Burrow: "Burrow #42"}type Gopher struct {
Name string
Habitat // embedded
}
g := Gopher{Name: "Gopher", Burrow: "Burrow #42"}And function type inference is generalized to apply anywhere a generic function is assigned or converted to a matching function type. Composite literals, type conversions, and channel sends now infer type arguments without you spelling them out.
Post-quantum crypto is no longer opt-in
The security story holds up as more than a language release. The new crypto/mldsa package implements the ML-DSA signature scheme from FIPS 204, and it's not sitting in a corner: crypto/x509 now handles ML-DSA private keys, public keys, and signatures, and crypto/tls supports ML-DSA signatures in TLS 1.3 via new MLDSA44, MLDSA65, and MLDSA87 signature schemes.
TLS also picks up the MLKEM1024 key exchange, which you can enable by adding it to Config.CurvePreferences. Between the signature scheme and the key exchange, the pieces are in place to run largely post-quantum TLS handshakes from the standard library.
encoding/json gets a v2, and your current code gets faster
The release ships two new packages. encoding/json/v2 is a major revision of the old API: high-level Marshal/Unmarshal plus lower-level streaming entry points, all accepting variadic Options to configure behavior. It defaults to stricter, more interoperable rules than v1. It rejects invalid UTF-8 in JSON strings and rejects duplicate names within an object.
Alongside it, encoding/json/jsontext handles low-level syntactic processing. It operates on a Token/Value stream through a state machine that guarantees the result is valid JSON.
The part most existing programs care about: encoding/json is now backed by the v2 implementation. Behavior is preserved and the v1 API stays supported, but unmarshaling is significantly faster, with marshal performance broadly at parity. If anything breaks, you can restore the old implementation with GOEXPERIMENT=nojsonv2. Backwards compatibility is not an "or": v1 keeps working alongside the new defaults.
The runtime quietly got more efficient
Two runtime improvements are worth knowing, even if they aren't as loud as the language changes.
Memory allocation is now size-specialized. The compiler generates calls to size-specific allocation routines, cutting the cost of small (under 80-byte) allocations by up to 30%. For allocation-heavy programs that works out to about a 1% overall gain, at the cost of roughly 60 KB of binary size. It's already on by default, with GOEXPERIMENT=nosizespecializedmalloc to opt out until it's removed in 1.28.
The goroutineleak profile, an experimental feature in 1.26, is now generally available in runtime/pprof and at /debug/pprof/goroutineleak. It reports goroutines permanently blocked on a channel, mutex, or cond that can never become unblocked. The clever part is that detection leans on the garbage collector: if a goroutine is blocked on a primitive that's unreachable, nothing can ever wake it. It won't catch every leak. Primitives reachable through globals or runnable goroutine locals can slip through, but it catches a large class of real hangs. Credit goes to Vlad Saioc at Uber.
Tooling and odds and ends
go docnow acceptspackage@version, sogo doc example.com/[email protected]works, and a new-exflag lists executable examples.go fixgains four modernizers:atomictypes,embedlit,slicesbackward, andunsafefuncs.- For modules declaring Go 1.27 or later,
go mod tidynow consolidates a messygo.modfull of scatteredrequireblocks back into the standard two-block direct/indirect layout. go testruns thestdversionvet check by default, flagging use of standard-library symbols too new for the file's configured Go version.stringsandbytesboth get aCutLasthelper, and the oldasynctimerchanGODEBUG setting is gone for good.- A new
uuidpackage generates and parses UUIDs natively, and an experimentalsimdpackage (behindGOEXPERIMENT=simd) provides portable, vector-size-agnostic SIMD.
On the platforms side, macOS 13 Ventura is now the minimum, and the big-endian ppc64 Linux port has moved to the ELFv2 ABI, which also unlocks cgo, PIE, and external linking there.
The release keeps the Go 1 compatibility promise, so almost all existing programs should compile and run as before. Generic methods is a genuinely long-awaited feature, but the post-quantum work and the encoding/json migration are the parts that will quietly show up in your dependency tree and your handshake, not because you configured anything, but because the default changed. That's usually the most interesting kind of release.