Go 1.27: Generic Methods, JSON v2 by Default, and Post-Quantum Signatures
— go, golang, go-1.27, release-notes, generics — 9 min read
Go 1.27 is a bigger language release than most. After years of the restriction standing, methods can now declare their own type parameters, and encoding/json moves onto the faster v2 engine by default, so every program that touches JSON gets a quicker unmarshal without changing a line. Around those two headliners sit post-quantum signatures through a new crypto/mldsa package (ML-DSA, FIPS 204) wired into crypto/x509 and crypto/tls, a standard uuid package that lets you drop a common dependency, small allocations that are up to 30 percent faster for objects under 80 bytes, and a goroutine leak profile that is now GA. One upgrade note stands out before anything else: Go 1.27 requires macOS 13 Ventura, and go test now runs the stdversion vet check by default.
Previous release: Go 1.26. This is the latest release in this series.
Methods can now carry their own type parameters
Since 1.18, methods could not have their own type parameters, which blocked common patterns like a Map method that changes a container's element type. Go 1.27 removes that restriction and finishes a long-running piece of the generics story.
A method may now declare its own type parameters (proposal 77273). Before, only the type could be generic, so a method that needed a fresh type parameter had to be a free function. Now it can be a method.
type Set[T comparable] map[T]struct{}
// Previously impossible: a method with its own type parameter U.func (s Set[T]) Map[U comparable](f func(T) U) Set[U] { out := make(Set[U]) for v := range s { out[f(v)] = struct{}{} } return out}Notice Map introduces U, independent of the receiver's T. The standard library already uses this: math/rand/v2 gained a generic Rand.N method.
Generic methods were left out of the original 1.18 generics because they complicate method sets and interface satisfaction: a generic method cannot be called through an interface, since the interface would not know which type to instantiate. Go 1.27 allows generic methods but keeps that constraint, so you can write func (s Set[T]) Map[U comparable](...) as a method, but you cannot put a generic method in an interface. Knowing that boundary saves you a confusing compile error (proposal 77273).
encoding/json now runs on the v2 engine
The original encoding/json had awkward behaviours and left performance on the table. The v2 rewrite, experimental since 1.25, is now the default engine, so every program that marshals or unmarshals JSON gets faster without changing a line.
This is the change every JSON-using program gets. The v2 rewrite of JSON, experimental since 1.25, is now the default: encoding/json is backed by the v2 implementation, and the encoding/json/v2 and encoding/json/jsontext packages are available directly (release notes, proposal 71497).
encoding/json ──▶ (Go 1.27) backed by the v2 engine unmarshal significantly faster, marshal at parityCaption: the default JSON path now runs on v2, with no code change.
Your existing json.Marshal and json.Unmarshal calls are unchanged and faster. If you want the new API and options directly, import v2:
import jsonv2 "encoding/json/v2"
data, err := jsonv2.Marshal(v)Notice you only need v2 explicitly for its new configuration options; the standard encoding/json already routes through it. If v2 changes a behaviour your code depends on, opt out with GOEXPERIMENT=nojsonv2, though that is expected to be removed later.
Making v2 the default engine behind the existing encoding/json API, rather than forcing everyone to a new import, is the compatible way to ship a rewrite: you get the speedup for free, and only reach for encoding/json/v2 when you want its new options.
Everything else worth knowing
The rest of 1.27 is a wide set of smaller improvements across the language, toolchain, runtime, and standard library.
Field selectors as struct-literal keys
A key in a struct literal can now be any valid field selector, including a promoted or nested field, not just a top-level field name (proposal 9859).
type Inner struct{ ID int }type Outer struct{ Inner }
// Now valid: set a promoted field directly in the literal.o := Outer{Inner.ID: 42}Notice this removes a small but frequent annoyance when initializing structs with embedded fields.
Generalized function type inference
Function type inference now applies in all contexts where a generic function is assigned to, or converted to, a matching function type (proposal 77245). In practice you write fewer explicit type arguments when passing generic functions around. Existing code keeps working; this only lets you omit more.
go test runs stdversion by default
go test now runs the stdversion vet check automatically. It reports use of standard library symbols that are newer than the go directive in your go.mod allows (release notes). This catches a real bug class: calling a 1.27 API while your module claims go 1.24, which would fail for users on older toolchains.
go test ./...# now also fails if you use a stdlib symbol too new for your go directiveNotice this is a correctness gain, but it can surface latent issues on first upgrade. Fix them by raising the go directive or not using the too-new symbol.
go fix gains modernizers, and other changes
go fix, rebuilt in 1.26, adds modernizers atomictypes, embedlit, slicesbackward, and unsafefuncs. go doc gains package@version syntax and an -ex option to show examples. go mod tidy merges duplicate require blocks for go 1.27 modules. The go command dropped Bazaar (bzr) support and now accepts response files (@file) for the low-level tools.
Faster small allocations
The compiler now generates size-specialized allocation routines, cutting the cost of some small allocations (under 80 bytes) by up to 30 percent (release notes). The Go team expects about a 1 percent overall improvement in real allocation-heavy programs, at the cost of roughly 60 KB more binary size. Opt out with GOEXPERIMENT=nosizespecializedmalloc, which is expected to be removed in 1.28.
The goroutine leak profile is GA
The experimental goroutine leak profile from 1.26 is now generally available. Read it from runtime/pprof as the goroutineleak profile, or over HTTP at /debug/pprof/goroutineleak (release notes).
/debug/pprof/goroutineleak ──▶ goroutines that are blocked and unreachableCaption: the goroutine leak profile surfaces goroutines that will never make progress.
Adopt this if you have ever chased a slow goroutine leak; it turns a hard problem into a profile.
Post-quantum signatures with crypto/mldsa
The new crypto/mldsa package implements ML-DSA, the post-quantum signature standard (FIPS 204). crypto/x509 can parse and use ML-DSA keys and signatures, and crypto/tls adds the MLDSA44, MLDSA65, and MLDSA87 signature schemes (release notes). Adopt if your threat model includes harvest-now-decrypt-later or you need FIPS 204 signatures.
A standard uuid package
Go now ships a uuid package in the standard library, so a UUID (Universally Unique Identifier) no longer needs a third-party dependency for most uses. Adopt when you want to drop a small external module.
Other additions
bytes.CutLastandstrings.CutLastsplit on the last occurrence of a separator, mirroringCut.- Unicode support moved from version 15 to 17.
crypto/tlsadds theMLKEM1024key exchange.- Experimental
simdandsimd/archsimdpackages gain arm64 Neon and WebAssembly 128-bit support (behindGOEXPERIMENT=simd).
Removed or behaviour-changed in 1.27
| Item | Replacement | Migration action | Source |
|---|---|---|---|
encoding/json v1 engine as default | v2 engine (transparent) | None; opt out with GOEXPERIMENT=nojsonv2 if needed | release notes |
time channels buffered behaviour (asynctimerchan GODEBUG) | Channels are now always unbuffered | Verify timer-channel code | release notes |
Bazaar (bzr) VCS support in go | git and others | Move repos off bzr | release notes |
| macOS versions before 13 | macOS 13 Ventura or later | Upgrade build and CI macOS | release notes |
Several locked GODEBUG settings (tlsunsafeekm, tls3des, tls10server, and more) removed | Their permanent defaults | Remove overrides | release notes |
GODEBUG settings introduced or defaulted
| Setting | Effect | Note | Source |
|---|---|---|---|
nojsonv2 (GOEXPERIMENT) | Disable the v2 JSON engine | Opt-out expected removed later | release notes |
tracebacklabels | Disable pprof labels in tracebacks (=0) | Added in 1.26; applies to go 1.27+ modules | release notes |
x509sslcertoverrideplatform | Control SystemCertPool honoring SSL_CERT_FILE/SSL_CERT_DIR on Windows and macOS (=0 to disable) | New in 1.27 | release notes |
Moving to 1.27 without surprises
The compatibility promise holds, so most code builds unchanged. A few things can bite on first upgrade:
go testfails on too-new stdlib use. Thestdversioncheck can surface latent version-skew bugs on first upgrade. Fix by raising thegodirective or avoiding the symbol.- JSON behaviour may shift subtly. v2 is at parity for marshal and faster for unmarshal, but some edge cases differ. Test JSON-heavy code and keep
GOEXPERIMENT=nojsonv2as an escape hatch. timechannels are unbuffered. Code that relied on the old buffered timer-channel behaviour may deadlock or change timing.- macOS 13 required. Builds and CI on older macOS will fail.
The stdversion behaviour and traceback labels are gated by the go directive in go.mod; the JSON engine and allocation changes apply as soon as you build with 1.27.
1. install Go 1.27 (go install golang.org/dl/go1.27@latest, then go1.27 download)2. run: go build ./... && go test ./... (watch for new stdversion failures)3. test JSON-heavy code paths under the v2 engine4. update macOS build/CI images to macOS 13+5. run go fix ./... for the new modernizers6. bump the go directive only when you want 1.27 features7. rollback: pin the previous toolchain, or set GOEXPERIMENT=nojsonv2 for JSON onlyCaption: recommended upgrade path to Go 1.27.
Specifics:
- Rebuild and test. The compatibility promise holds, so most code builds unchanged.
- The two most likely surprises are the
stdversioncheck firing and a JSON edge case. Both have clear fixes. - Rollback: a toolchain pin reverts everything;
GOEXPERIMENT=nojsonv2reverts only JSON.
Once you are on 1.27, a few small experiments make the new surface concrete:
- Convert a helper function that changes a container's element type into a generic method.
- Benchmark a JSON-heavy endpoint under 1.27 and compare unmarshal time to 1.26.
- Capture a
goroutineleakprofile from a service you suspect leaks goroutines. - Replace a third-party UUID import with the standard
uuidpackage. - Run
go test ./...and fix anystdversionfindings by aligning yourgodirective.
This concludes the Go 1.26 and 1.27 series. Start at Go 1.26 for the Green Tea GC release.
Further reading
Release and dates:
Language and standard library:
- Generic methods: proposal 77273
- Field-selector struct keys: proposal 9859
- Generalized inference: proposal 77245
- JSON v2: proposal 71497, encoding/json/v2