- Published on
Go 1.27: small changes that feel useful
- Authors

- Name
- Amjad Hossain
Go 1.27 is here. Generic methods are the change that caught my eye. They fix a limit that has felt awkward since generics arrived. The rest of the release cleans up smaller problems.
Every example below has a Playground link. You can run the code yourself.
Generic methods are finally here
Before Go 1.27, a method could not add a new type. We often had to write a helper function instead. That felt odd when the code belonged with a type.
Go 1.27 fixes this. Here is a list that turns numbers into labels:
type List[T any] []T
func (items List[T]) Map[U any](convert func(T) U) List[U] {
result := make(List[U], len(items))
for i, item := range items {
result[i] = convert(item)
}
return result
}
numbers := List[int]{1, 2, 3}
labels := numbers.Map(func(n int) string {
return fmt.Sprintf("Item %d", n)
})
fmt.Println(labels) // [Item 1 Item 2 Item 3]
Run the generic method example on the Go Playground.
Here, U is the type we want back. Map changes a List[int] into a List[string]. Before Go 1.27, Map had to be a separate function. Now it can be a method on List.
There is one limit. Interfaces cannot have generic methods. A generic method also cannot implement an interface method. This feature works best with concrete types such as List.
Embedded structs need less typing
This is a small change. It makes structs easier to set up. We can now set an embedded field directly:
type Address struct {
City string
}
type User struct {
Name string
Address
}
user := User{
Name: "John",
City: "USA",
}
Run the embedded struct example on the Go Playground.
Before Go 1.27, City had to sit inside Address: Address{...}. The new code is shorter. It is still easy to read.
UUIDs are now built in
I have added a UUID package to many Go projects. Go 1.27 finally includes one:
package main
import (
"fmt"
"uuid"
)
func main() {
id := uuid.New()
fmt.Println(id)
}
Run the UUID example on the Go Playground.
The package can create version 4 and version 7 UUIDs. It can also read UUID strings. This means one less package to install.
It does not plug directly into database/sql. You may need to read an ID as a string and then parse it. google/uuid is still easier for database-heavy projects.
Post-quantum signatures are here
Go 1.27 adds crypto/mldsa. It creates signatures that are designed to resist future quantum computers.
The code feels like other signing code in Go:
privateKey, err := mldsa.GenerateKey(mldsa.MLDSA44())
if err != nil {
log.Fatal(err)
}
message := []byte("deploy version 1.27")
signature, err := privateKey.Sign(nil, message, nil)
if err != nil {
log.Fatal(err)
}
err = mldsa.Verify(privateKey.PublicKey(), message, signature, nil)
fmt.Println("valid:", err == nil)
fmt.Println("public key:", len(privateKey.PublicKey().Bytes()), "bytes")
fmt.Println("signature:", len(signature), "bytes")
valid: true
public key: 1312 bytes
signature: 2420 bytes
Run the ML-DSA example on the Go Playground.
Those sizes use ML-DSA-44, the smallest option. The large keys and signatures are the main tradeoff. They can add real cost to certificates, network messages, and stored data.
JSON gets a careful upgrade
JSON also gets an update. The new encoding/json/v2 package gives us more control. It also handles bad input more carefully. It rejects invalid text and repeated object names.
We do not need to change old projects right away. The existing encoding/json API still works. It now uses the newer code underneath. Reading JSON is also faster in many programs.
One detail may affect tests. JSON error messages can have different text. Avoid tests that compare the full error message.
A few practical improvements
- A new
goroutineleakprofile finds goroutines that will never finish. It is available at/debug/pprof/goroutineleak. - Small memory allocations are faster. We do not need to change our code.
go doc example.com/pkg@v1.2.3shows the docs for an exact package version.go mod tidynow cleans up repeatedrequireblocks ingo.mod.strings.CutLastandbytes.CutLastmake it easier to split at the final separator.
My take
Generic methods are the main change for me. They let useful code live next to the type it belongs to. The UUID package is a smaller change. I will probably use it more often.
The official Go 1.27 release notes list every change. The Go release announcement gives a shorter overview.