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:

GO
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)
}
Output
"#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:

GO
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)
}
Output
{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:

GO
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())
}
Output
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

GO
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)
}
Output
assets/img logo.final.png
-4 1
example.com mirror.example.com
true
PackageWhat's new
crypto/mldsaML-DSA, a post-quantum signature scheme (FIPS 204); supported in crypto/x509 and TLS 1.3
crypto/tlsML-KEM-1024 key exchange available; Config.Rand deprecated
net/httpHTTP/2 servers honour client priority signals; response bodies are drained on Close to reuse connections
net/http/httptestNewTestServer, an in-memory server for use with testing/synctest
testing/synctestSleep, combining time.Sleep and synctest.Wait
hash/maphashA Hasher interface for future generic hash tables
unicodeUpgraded 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 %w when the value type is the error (lesson 45), a latent bug that breaks errors.Is.
  • go test runs the stdversion check by default: it flags uses of standard library functions newer than your module's go line.
  • go doc accepts package@version, and -ex lists or prints runnable examples.
  • go fix gains more modernizers, which rewrite code to newer idioms automatically (lesson 68).
  • go mod tidy merges scattered require blocks 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's goroutineleak profile and /debug/pprof/goroutineleak report goroutines blocked forever.
  • Crash tracebacks include goroutine labels, and timer channels are now always unbuffered (the old asynctimerchan setting 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:

  • new accepts an expression: new(34) gives a pointer to an int holding 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 simpler errors.As (lesson 45).
  • The "Green Tea" garbage collector became the default, cutting garbage collection overhead noticeably in many programs.
  • go fix was 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 ./...
Next: best practices and the tools that enforce them.