What's New in Go 1.27
Go 1.27, released in August 2026, is one of the bigger releases in years for the language itself: methods can finally have their own type parameters. It also brings a new JSON implementation, a uuid package in the standard library, a post-quantum signature scheme, new vet checks and faster memory allocation. This lesson summarises the changes that matter most in everyday code, with examples you can run — and a quick look back at Go 1.26.
Language: generic methods
A method can now declare type parameters of its own (lesson 49). Operations that change a type — mapping a List[int] to a List[string], say — can live on the type instead of being package-level functions:
package main import ( "fmt" "strconv" ) type Box[T any] struct{ V T } func (b Box[T]) Map[U any](f func(T) U) Box[U] { return Box[U]{f(b.V)} } func main() { b := Box[int]{42}.Map(strconv.Itoa).Map(func(s string) string { return "#" + s }) fmt.Printf("%q\n", b.V) }
"#42"
Interface methods still can't have type parameters, and a generic method never satisfies an interface method.
Language: promoted fields in struct literals
A struct literal's keys may now name fields promoted from an embedded struct, not only the struct's own fields:
package main import "fmt" type Base struct { ID int Created string } type User struct { Base Name string } func main() { u := User{ID: 7, Created: "2026-10-08", Name: "Ana"} // ID and Created come from Base fmt.Printf("%+v\n", u) }
{Base:{ID:7 Created:2026-10-08} Name:Ana}Before Go 1.27 you had to write User{Base: Base{ID: 7, Created: "2026-10-08"}, Name: "Ana"}. The release also widens type inference when a generic function is used as a value of a matching function type, so it now works in more places than plain assignments and return statements.
As always, new language features are enabled by the go 1.27 line in go.mod; with an older line, the compiler reports that the feature "requires go1.27 or later".
A uuid package
Generating unique IDs no longer needs a third-party module. The new uuid package creates random (version 4) and time-ordered (version 7) UUIDs, and parses them:
package main import ( "fmt" "uuid" ) func main() { id := uuid.New() // random each run s := id.String() fmt.Println(len(s), s[14:15]) // 36 characters; the version digit is 4 ordered := uuid.NewV7() // starts with a timestamp, so IDs sort by creation time fmt.Println(ordered.String()[14:15]) parsed, err := uuid.Parse("f47ac10b-58cc-4372-a567-0e02b2c3d479") fmt.Println(parsed, err) _, err = uuid.Parse("not-a-uuid") fmt.Println(err != nil, uuid.Nil()) }
36 4 7 f47ac10b-58cc-4372-a567-0e02b2c3d479 <nil> true 00000000-0000-0000-0000-000000000000
Version 7 UUIDs are a good default for database primary keys, because new rows get IDs that sort after older ones. UUID implements text marshalling, so it works directly as a JSON field.
encoding/json/v2
The new encoding/json/v2 and encoding/json/jsontext packages are a major revision of JSON support, with options passed to each call and stricter defaults: case-sensitive field matching, rejection of duplicate names and invalid UTF-8, and nil slices encoded as [] (lesson 59). The classic encoding/json now runs on the new implementation — unmarshalling is significantly faster — while keeping its documented behaviour; only error message wording may differ.
Smaller library additions
package main import ( "fmt" "math/big" "math/rand/v2" "net/url" "strings" ) func main() { // strings.CutLast and bytes.CutLast: split around the last separator dir, file, _ := strings.CutLast("assets/img/logo.final.png", "/") fmt.Println(dir, file) // big.Int.Divide with a rounding mode q, r := new(big.Int).Divide(big.NewInt(-7), big.NewInt(2), new(big.Int), big.Floor) fmt.Println(q, r) // url.URL.Clone: a deep copy u, _ := url.Parse("https://example.com/search?q=go") c := u.Clone() c.Host = "mirror.example.com" fmt.Println(u.Host, c.Host) // (*rand.Rand).N: a generic method matching rand.N rng := rand.New(rand.NewPCG(1, 1)) fmt.Println(rng.N(int64(10)) < 10) }
assets/img logo.final.png -4 1 example.com mirror.example.com true
| Package | What's new |
|---|---|
crypto/mldsa | ML-DSA, a post-quantum signature scheme (FIPS 204); supported in crypto/x509 and TLS 1.3 |
crypto/tls | ML-KEM-1024 key exchange available; Config.Rand deprecated |
net/http | HTTP/2 servers honour client priority signals; response bodies are drained on Close to reuse connections |
net/http/httptest | NewTestServer, an in-memory server for use with testing/synctest |
testing/synctest | Sleep, combining time.Sleep and synctest.Wait |
hash/maphash | A Hasher interface for future generic hash tables |
unicode | Upgraded to Unicode 17 |
simd (experimental) | Portable SIMD vector types, enabled with GOEXPERIMENT=simd |
Tools
- go vet reports wrapping a pointer to an error type with
%wwhen the value type is the error (lesson 45), a latent bug that breakserrors.Is. - go test runs the
stdversioncheck by default: it flags uses of standard library functions newer than your module'sgoline. - go doc accepts
package@version, and-exlists or prints runnable examples. - go fix gains more modernizers, which rewrite code to newer idioms automatically (lesson 68).
- go mod tidy merges scattered
requireblocks into at most two: direct and indirect dependencies. - gofmt fixes a column-alignment inconsistency, so a few files may get small whitespace changes.
Runtime and performance
- Small allocations (under 80 bytes) use size-specialised code paths and are up to 30% cheaper.
- The goroutine leak profile, experimental in 1.26, is now standard:
runtime/pprof'sgoroutineleakprofile and/debug/pprof/goroutineleakreport goroutines blocked forever. - Crash tracebacks include goroutine labels, and timer channels are now always unbuffered (the old
asynctimerchansetting is gone). - On macOS, Go 1.27 requires macOS 13 Ventura or later.
Looking back: Go 1.26
If you're upgrading from an older version, Go 1.26 (February 2026) brought changes you'll also use often:
newaccepts an expression:new(34)gives a pointer to anintholding 34 (lesson 37).- Generic types may refer to themselves in their type parameter lists, as in
type Adder[A Adder[A]] interface{…}(lesson 48). errors.AsType, a generic and simplererrors.As(lesson 45).- The "Green Tea" garbage collector became the default, cutting garbage collection overhead noticeably in many programs.
go fixwas rebuilt around modernizers.
Upgrading
Thanks to the Go 1 compatibility promise, upgrading is usually just installing the new toolchain and running your tests. To use the new language features in a module, raise its go line:
go get go@1.27 go mod tidy go fix ./... go test ./...