Reference for what changed in Go 1.27 — use when writing or reviewing Go code in a `go 1.27`+ module so you do not fall back on pre-1.27 training-data assumptions. Covers new language features (generic methods), new and changed standard-library APIs (`encoding/json/v2`, `uuid`, `crypto/mldsa`, `strings.CutLast`, …), and dangerous behavior changes (time channels now unbuffered, `net` `UnixConn` returning raw `io.EOF`, `go tool trace -http` binding localhost-only). Triggers include "go 1.27", "golang 1.27", "go1.27", "1.27 の変更点", "Go 1.27 で開発", "is this valid in go 1.27".
Install
npx skillscat add handlename/agent-skills/go1-27-changes Install via the SkillsCat registry.
Go 1.27 Changes (for LLM-assisted development)
Overview
Go 1.27 was released in August 2026. If your training data predates it, you do not reliably know what changed — this skill is the source of truth for the parts that affect how you write Go code.
Scope: this reference emphasizes developer-facing changes — language, standard library, and go command behavior that changes code or workflows — and it deliberately foregrounds gotchas: places where pre-1.27 habits now produce wrong code or wrong behavior. Runtime/compiler/linker/ports changes are covered briefly at the end for build-error triage.
Official release notes: https://go.dev/doc/go1.27
How to use this reference
- When editing Go, first confirm the module targets 1.27 (see Verification). If it targets an older version, ignore the "new API" sections and treat only the removed-
GODEBUG/ requirement notes as relevant to upgrades. - Prefer the new idioms below over the pre-1.27 workarounds you were trained on.
- Verify exact signatures before emitting code. Item descriptions here are accurate, but a few precise signatures are marked (verify) — confirm them at the linked
pkg.go.devpage rather than guessing. Never invent an API shape.
Instructions
1. Language changes
Generic methods (biggest change)
Methods may now declare their own type parameters — previously you had to hoist such logic into a package-scoped generic function.
// Before 1.27: illegal — a method could not add type parameters.
// func (r *Rand) N[Int intType](n Int) Int { ... } // compile error
// You wrote a top-level function instead:
func N[Int intType](r *Rand, n Int) Int { /* ... */ }
// Go 1.27: legal — the method carries its own type parameter.
func (r *Rand) N[Int intType](n Int) Int { /* ... */ }Restriction to remember: interface methods may not declare type parameters, and interface methods cannot be implemented by generic methods. So you cannot put N[Int intType]() in an interface.
Struct literal keys accept any field selector
A key in a struct literal may now be any valid field selector (e.g. a promoted/embedded field path), not just a top-level field name. When you see a keyed struct literal using a nested selector, it is valid 1.27 syntax. (verify the exact selector forms at the release notes if a specific case matters.)
Generalized function type inference
Type inference now applies in all contexts where a generic function is assigned to, or converted to, a matching function type — so more assignments of generic functions to typed function variables compile without explicit instantiation.
2. New standard-library packages — reach for these instead of old workarounds
| Package | Import path | Use it for | Pre-1.27 habit to drop |
|---|---|---|---|
| JSON v2 | encoding/json/v2 |
New, faster, stricter JSON | Don't assume encoding/json is the only option |
| JSON tokens | encoding/json/jsontext |
Low-level JSON syntax (Encoder, Decoder, Token, Value) |
Hand-rolling token scanners |
| UUID | uuid (top-level) |
Generating/parsing UUIDs | Pulling in github.com/google/uuid — check if stdlib suffices |
| ML-DSA | crypto/mldsa |
Post-quantum signatures (FIPS 204) | — |
| SIMD (experimental) | simd, simd/archsimd |
Vector ops; needs GOEXPERIMENT=simd |
— |
encoding/json/v2
Exact entry points: Marshal, MarshalWrite, MarshalEncode, Unmarshal, UnmarshalRead, UnmarshalDecode. All take variadic Options.
import jsonv2 "encoding/json/v2"
data, err := jsonv2.Marshal(v) // v2 API
err = jsonv2.Unmarshal(data, &v)Gotcha — stricter defaults: v2 rejects invalid UTF-8 in JSON strings and rejects duplicate object names, where v1 tolerated both. Code that round-trips lax JSON under encoding/json may now error under v2. The v1 encoding/json package still exists and is now backed by v2, but keeps v1 defaults; don't assume switching packages is behavior-neutral.
For uuid, the package exists to generate and parse UUIDs, but the release notes do not pin the function names — look up the exact API at https://pkg.go.dev/uuid before calling it (do not assume google/uuid-style names).
3. Behavior-change gotchas (same code, different result)
These are the highest-risk items: existing-looking code compiles but behaves differently than pre-1.27.
- Time channels are now always unbuffered (synchronous). The
asynctimerchanGODEBUG (added in 1.23) is permanently removed; channels created by packagetime(e.g.time.Timer.C,time.Ticker.C) are always unbuffered regardless of GODEBUG. Do not rely on a buffered tick being retained while you were busy — semantics are synchronous delivery. Review timer/ticker draining logic. See https://go.dev/doc/go1.27. netUnixConnreturns rawio.EOF.UnixConnread methods now returnio.EOFdirectly instead of wrapping it in a*net.OpError. Code that type-asserts the error to*net.OpErroron EOF will stop matching — compare witherrors.Is(err, io.EOF).go tool trace -httpbinds localhost by default. Given only a port (e.g.-http=:6060), it now listens on localhost only (consistent withgo tool pprof). To listen on all interfaces you must be explicit:-http=0.0.0.0:6060. Fix any container/remote workflow that relied on the old all-interfaces default.compress/flateoutput may differ. Compression speed improved and theWriter's exact byte output can differ from 1.26. Golden-file/byte-exact tests and reproducibility checks over compressed bytes may need regenerating; decompression is unaffected.- Function-literal identity may change. The compiler now generates simpler, consistent names for function literals and may deduplicate identical literals that capture the same closure data. Code that compared function pointers for equality (a fragile pattern already) can observe different results.
4. Handy new/changed stdlib APIs
Prefer these where they fit; confirm exact signatures at the linked package before use.
| API | What it does | Note |
|---|---|---|
strings.CutLast, bytes.CutLast |
Slice around the last occurrence of a separator (mirror of Cut, which uses the first) |
Signature shape parallels Cut(s, sep) (before, after, found) |
net/url URL.Clone, Values.Clone |
Deep-copy a *URL / Values |
No more manual struct copies |
math/rand/v2 Rand.N |
Generic method matching the top-level N function |
func (r *Rand) N[Int intType](n Int) Int |
net/http/httptest.NewTestServer |
Server on an in-memory fake network, made for testing/synctest |
(verify signature at pkg.go.dev/net/http/httptest) |
testing/synctest.Sleep |
Combines time.Sleep + synctest.Wait |
Use inside synctest bubbles |
math/big Int.Divide |
Quotient+remainder with rounding modes Trunc, Floor, Round, Ceil |
(verify exact signature at pkg.go.dev/math/big) |
database/sql.ConvertAssign |
Exposed value-conversion helper | — |
database/sql/driver.RowsColumnScanner |
Driver interface for direct column scanning | — |
bytes / strings |
(see CutLast above) |
— |
unicode |
Upgraded Unicode 15 → Unicode 17 | New code points/properties available |
5. go command & toolchain changes (affect workflows and reviews)
vetstdversionruns ingo testby default: flags use of standard-library symbols newer than the Go version declared ingo.mod. If you write 1.27 stdlib APIs in a module still declaringgo 1.26, tests now report it — bump thegodirective.go docgainspackage@version: e.g.go doc example.com/pkg@v1.2.3; new-exflag lists executable examples, and passing an example name prints its source.go fixmodernizers changed: addedatomictypes,embedlit,slicesbackward,unsafefuncs; removedfmtappendf; renamedwaitgroup→waitgroupgo. Use the new names when invoking analyzers.go mod tidymerges require blocks: forgo 1.27+modules it collapses duplicaterequireblocks into at most two (direct, then indirect), preserving comment blocks. Expect a one-time diff ingo.modshape.go test -jsonaddsOutputType:"Action":"output"lines may carry an optional"OutputType"field ("error","error-continue","frame"). Tooling parsing test JSON can use it but must tolerate its absence.- Response files (
@file):compile,link,asm,cgo,cover,packnow accept GCC-style@fileargument files. crypto/tlsadditions:MLKEM1024key exchange andMLDSA44/65/87signature schemes are supported; several legacyGODEBUGs were permanently removed (tlsunsafeekm,tlsrsakex,tls3des,tls10server,x509keypairleaf) — code depending on those escape hatches will break on upgrade.
6. Upgrade / build-triage notes (brief)
- macOS 13 Ventura or later is required. Older macOS is discontinued.
bzr(Bazaar) VCS support removed from thegocommand.- Removed
GODEBUGsettings (asynctimerchan,gotypesalias, thecrypto/tlslist above,x509keypairleaf): setting them ingo.modgodebug///go:debugto an old value now errors; to the final default value is accepted. - Runtime: faster small-object allocation; new generally-available
goroutineleakprofile (/debug/pprof/goroutineleak); goroutinepproflabels appear in traceback headers forgo 1.27+modules (disable withGODEBUG=tracebacklabels=0). - PowerPC 64-bit big-endian on Linux now uses the ELFv2 ABI (needs kernel 3.13+); cgo/PIE/external linking gained support there.
Verification
Before relying on anything above in generated code:
Confirm the toolchain/module is on 1.27:
go version # expect go1.27 or later grep -E '^go [0-9]' go.mod # expect "go 1.27" (or higher)If the module declares an older
godirective, new-API sections do not apply until the directive is bumped;vet'sstdversioncheck will otherwise flag the code.Confirm exact signatures for any item marked (verify) (and for
uuid) athttps://pkg.go.dev/<import-path>— e.g. https://pkg.go.dev/encoding/json/v2, https://pkg.go.dev/math/big, https://pkg.go.dev/uuid. Do not emit an invented signature.When a gotcha in §3 applies, re-check the specific code path (timer draining,
*net.OpErrortype assertions on EOF,go tool tracebind address, byte-exactflateassertions, function-pointer comparisons) rather than assuming pre-1.27 behavior.Cross-check any uncertain claim against the official notes: https://go.dev/doc/go1.27.