Go 1.25 Release Notes

DRAFT RELEASE NOTES — Introduction to Go 1.25

Go 1.25 is not yet released. These are work-in-progress release notes. Go 1.25 is expected to be released in August 2025.

Changes to the language

There are no languages changes that affect Go programs in Go 1.25. However, in the language specification the notion of core types has been removed in favor of dedicated prose. See the respective blog post for more information.

Tools

Go command

The go build -asan option now defaults to doing leak detection at program exit. This will report an error if memory allocated by C is not freed and is not referenced by any other memory allocated by either C or Go. These new error reports may be disabled by setting ASAN_OPTIONS=detect_leaks=0 in the environment when running the program.

The Go distribution will include fewer prebuilt tool binaries. Core toolchain binaries such as the compiler and linker will still be included, but tools not invoked by build or test operations will be built and run by go tool as needed.

The new go.mod ignore directive can be used to specify directories the go command should ignore. Files in these directories and their subdirectories will be ignored by the go command when matching package patterns, such as all or ./..., but will still be included in module zip files.

The new go doc -http option will start a documentation server showing documentation for the requested object, and open the documentation in a browser window.

The new go version -m -json option will print the JSON encodings of the runtime/debug.BuildInfo structures embedded in the given Go binary files.

The go command now supports using a subdirectory of a repository as the path for a module root, when resolving a module path using the syntax <meta name="go-import" content="root-path vcs repo-url subdir"> to indicate that the root-path corresponds to the subdir of the repo-url with version control system vcs.

The new work package pattern matches all packages in the work (formerly called main) modules: either the single work module in module mode or the set of workspace modules in workspace mode.

When the go command updates the go line in a go.mod or go.work file, it no longer adds a toolchain line specifying the command’s current version.

Vet

The go vet command includes new analyzers:

Runtime

Container-aware GOMAXPROCS

The default behavior of the GOMAXPROCS has changed. In prior versions of Go, GOMAXPROCS defaults to the number of logical CPUs available at startup (runtime.NumCPU). Go 1.25 introduces two changes:

  1. On Linux, the runtime considers the CPU bandwidth limit of the cgroup containing the process, if any. If the CPU bandwidth limit is lower than the number of logical CPUs available, GOMAXPROCS will default to the lower limit. In container runtime systems like Kubernetes, cgroup CPU bandwidth limits generally correspond to the “CPU limit” option. The Go runtime does not consider the “CPU requests” option.

  2. On all OSes, the runtime periodically updates GOMAXPROCS if the number of logical CPUs available or the cgroup CPU bandwidth limit change.

Both of these behaviors are automatically disabled if GOMAXPROCS is set manually via the GOMAXPROCS environment variable or a call to runtime.GOMAXPROCS. They can also be disabled explicitly with the GODEBUG settings containermaxprocs=0 and updatemaxprocs=0, respectively.

In order to support reading updated cgroup limits, the runtime will keep cached file descriptors for the cgroup files for the duration of the process lifetime.

New experimental garbage collector

A new garbage collector is now available as an experiment. This garbage collector’s design improves the performance of marking and scanning small objects through better locality and CPU scalability. Benchmark result vary, but we expect somewhere between a 10—40% reduction in garbage collection overhead in real-world programs that heavily use the garbage collector.

The new garbage collector may be enabled by setting GOEXPERIMENT=greenteagc at build time. We expect the design to continue to evolve and improve. To that end, we encourage Go developers to try it out and report back their experiences. See the GitHub issue for more details on the design and instructions for sharing feedback.

Change to unhandled panic output

The message printed when a program exits due to an unhandled panic that was recovered and repanicked no longer repeats the text of the panic value.

Previously, a program which panicked with panic("PANIC"), recovered the panic, and then repanicked with the original value would print:

panic: PANIC [recovered]
  panic: PANIC

This program will now print:

panic: PANIC [recovered, repanicked]

VMA names on Linux

On Linux systems with kernel support for anonymous virtual memory area (VMA) names (CONFIG_ANON_VMA_NAME), the Go runtime will annotate anonymous memory mappings with context about their purpose. e.g., [anon: Go: heap] for heap memory. This can be disabled with the GODEBUG setting decoratemappings=0.

Compiler

The compiler and linker in Go 1.25 now generate debug information using DWARF version 5. The newer DWARF version reduces the space required for debugging information in Go binaries, and reduces the time for linking, especially for large Go binaries. DWARF 5 generation can be disabled by setting the environment variable GOEXPERIMENT=nodwarf5 at build time (for now, which may be removed in a future Go release).

The compiler has been fixed to ensure that nil pointer checks are performed promptly. Programs like the following, which used to execute successfully, will now panic with a nil-pointer exception:

package main

import "os"

func main() {
    f, err := os.Open("nonExistentFile")
    name := f.Name()
    if err != nil {
        return
    }
    println(name)
}

This program is incorrect in that it uses the result of os.Open before checking the error. The main result of os.Open can be a nil pointer if the error result is non-nil. But because of a compiler bug, this program ran successfully under Go versions 1.21 through 1.24 (in violation of the Go spec). It will no longer run successfully in Go 1.25. If this change is affecting your code, the solution is to put the non-nil error check earlier in your code, preferably immediately after the error-generating statement.

The compiler can now allocate the backing store for slices on the stack in more situations, which improves performance. This change has the potential to amplify the effects of incorrect unsafe.Pointer usage, see for example issue 73199. In order to track down these problems, the bisect tool can be used to find the allocation causing trouble using the -compile=variablemake flag. All such new stack allocations can also be turned off using -gcflags=all=-d=variablemakehash=n.

Linker

The linker now accepts a -funcalign=N command line option, which specifies the alignment of function entries. The default value is platform-dependent, and is unchanged in this release.

Standard library

New testing/synctest package

The new testing/synctest package provides support for testing concurrent code.

The Test function runs a test function in an isolated “bubble”. Within the bubble, time package functions operate on a fake clock.

The Wait function waits for all goroutines in the current bubble to block.

New experimental encoding/json/v2 package

Go 1.25 includes a new, experimental JSON implementation, which can be enabled by setting the environment variable GOEXPERIMENT=jsonv2 at build time.

When enabled, two new packages are available:

In addition, when the “jsonv2” GOEXPERIMENT is enabled:

The new implementation performs substantially better than the existing one under many scenarios. In general, encoding performance is at parity between the implementations and decoding is substantially faster in the new one. See the github.com/go-json-experiment/jsonbench repository for more detailed analysis.

See the proposal issue for more details.

We encourage users of encoding/json to test their programs with GOEXPERIMENT=jsonv2 enabled to help detect any compatibility issues with the new implementation.

We expect the design of encoding/json/v2 to continue to evolve. We encourage developers to try out the new API and provide feedback on the proposal issue.

Minor changes to the library

archive/tar

The Writer.AddFS implementation now supports symbolic links for filesystems that implement io/fs.ReadLinkFS.

crypto

MessageSigner is a new signing interface that can be implemented by signers that wish to hash the message to be signed themselves. A new function is also introduced, SignMessage, which attempts to update a Signer interface to MessageSigner, using the MessageSigner.SignMessage method if successful, and Signer.Sign if not. This can be used when code wishes to support both Signer and MessageSigner.

crypto/ecdsa

The new ParseRawPrivateKey, ParseUncompressedPublicKey, PrivateKey.Bytes, and PublicKey.Bytes functions and methods implement low-level encodings, replacing the need to use crypto/elliptic or math/big functions and methods.

crypto/elliptic

The hidden and undocumented Inverse and CombinedMult methods on some Curve implementations have been removed.

crypto/sha3

The new SHA3.Clone method implements hash.Cloner.

crypto/tls

The new ConnectionState.CurveID field exposes the key exchange mechanism used to establish the connection.

The new Config.GetEncryptedClientHelloKeys callback can be used to set the EncryptedClientHelloKeys for a server to use when a client sends an Encrypted Client Hello extension.

SHA-1 signature algorithms are now disallowed in TLS 1.2 handshakes, per RFC 9155. They can be re-enabled with the tlssha1=1 GODEBUG option.

When FIPS 140-3 mode is enabled, Extended Master Secret is now required in TLS 1.2, and Ed25519 and X25519MLKEM768 are now allowed.

TLS servers now prefer the highest supported protocol version, even if it isn’t the client’s most preferred protocol version.

crypto/x509

CreateCertificate, CreateCertificateRequest, and CreateRevocationList can now accept a crypto.MessageSigner signing interface as well as crypto.Signer. This allows these functions to use signers which implement “one-shot” signing interfaces, where hashing is done as part of the signing operation, instead of by the caller.

CreateCertificate now uses truncated SHA-256 to populate the SubjectKeyId if it is missing. The GODEBUG setting x509sha256skid=0 reverts to SHA-1.

debug/elf

The debug/elf package adds two new constants:

go/ast

The FilterPackage, PackageExports, and MergePackageFiles functions, and the MergeMode type and its constants, are all deprecated, as they are for use only with the long-deprecated Object and Package machinery.

The new PreorderStack function, like Inspect, traverses a syntax tree and provides control over descent into subtrees, but as a convenience it also provides the stack of enclosing nodes at each point.

go/parser

The ParseDir function is deprecated.

go/token

The new FileSet.AddExistingFiles method enables existing Files to be added to a FileSet, or a FileSet to be constructed for an arbitrary set of Files, alleviating the problems associated with a single global FileSet in long-lived applications.

go/types

Var now has a Var.Kind method that classifies the variable as one of: package-level, receiver, parameter, result, or local variable, or a struct field.

The new LookupSelection function looks up the field or method of a given name and receiver type, like the existing LookupFieldOrMethod function, but returns the result in the form of a Selection.

hash

The new XOF interface can be implemented by “extendable output functions”, which are hash functions with arbitrary or unlimited output length such as SHAKE.

Hashes implementing the new Cloner interface can return a copy of their state. All standard library Hash implementations now implement Cloner.

hash/maphash

The new Hash.Clone method implements hash.Cloner.

io/fs

A new ReadLinkFS interface provides the ability to read symbolic links in a filesystem.

log/slog

GroupAttrs creates a group Attr from a slice of Attr values.

Record now has a Source method, returning its source location or nil if unavailable.

mime/multipart

The new helper function FieldContentDisposition builds multipart Content-Disposition header fields.

net

LookupMX and Resolver.LookupMX now return DNS names that look like valid IP address, as well as valid domain names. Previously if a name server returned an IP address as a DNS name, LookupMX would discard it, as required by the RFCs. However, name servers in practice do sometimes return IP addresses.

On Windows, the ListenMulticastUDP now supports IPv6 addresses.

On Windows, conversions between an os.File and a network connection are now supported. Specifcally, the FileConn, FilePacketConn, FileListener functions are now implemented, allowing getting the network connection or listener corresponding to an open file. The TCPConn.File, UDPConn.File, UnixConn.File, IPConn.File, TCPListener.File, and UnixListener.File methods are now also available, allowing access to the underlying os.File of the connection.

net/http

The new CrossOriginProtection implements protections against Cross-Site Request Forgery (CSRF) by rejecting non-safe cross-origin browser requests. It uses modern browser Fetch metadata, doesn’t require tokens or cookies, and supports origin-based and pattern-based bypasses.

os

On Windows, NewFile now supports handles opened for asynchronous I/O (that is, syscall.FILE_FLAG_OVERLAPPED is specified in the syscall.CreateFile call). These handles are associated with the Go runtime’s I/O completion port, which provides the following benefits for the resulting File:

This enhancement is especially beneficial for applications that communicate via named pipes on Windows.

Note that a handle can only be associated with one completion port at a time. If the handle provided to NewFile is already associated with a completion port, the returned File is downgraded to synchronous I/O mode. In this case, I/O methods will block an OS thread, and the deadline methods have no effect.

The filesystems returned by DirFS and Root.FS implement the new io/fs.ReadLinkFS interface. CopyFS supports symlinks when copying filesystems that implement io/fs.ReadLinkFS.

The Root type supports the following additional methods:

reflect

The new TypeAssert function permits converting a Value directly to a Go value of the given type. This is like using a type assertion on the result of Value.Interface, but avoids unnecessary memory allocations.

regexp/syntax

The \p{name} and \P{name} character class syntaxes now accept the names Any, ASCII, Assigned, Cn, and LC, as well as Unicode category aliases like \p{Letter} for \pL. Following Unicode TR18, they also now use case-insensitive name lookups, ignoring spaces, underscores, and hyphens.

runtime

Cleanup functions scheduled by AddCleanup are now executed concurrently and in parallel, making cleanups more viable for heavy use like the unique package. Note that individual cleanups should still shunt their work to a new goroutine if they must execute or block for a long time to avoid blocking the cleanup queue.

When GODEBUG=checkfinalizers=1 is set, the runtime will run diagnostics on each garbage collection cycle to find common issues with how the program might use finalizers and cleanups, such as those described in the GC guide. In this mode, the runtime will also regularly report the finalizer and cleanup queue lengths to stderr to help identify issues with long-running finalizers and/or cleanups.

The new SetDefaultGOMAXPROCS function sets GOMAXPROCS to the runtime default value, as if the GOMAXPROCS environment variable is not set. This is useful for enabling the new GOMAXPROCS default if it has been disabled by the GOMAXPROCS environment variable or a prior call to GOMAXPROCS.

runtime/pprof

The mutex profile for contention on runtime-internal locks now correctly points to the end of the critical section that caused the delay. This matches the profile’s behavior for contention on sync.Mutex values. The runtimecontentionstacks setting for GODEBUG, which allowed opting in to the unusual behavior of Go 1.22 through 1.24 for this part of the profile, is now gone.

runtime/trace

The new FlightRecorder provides a lightweight way to capture a trace of last few seconds of execution at a specific moment in time. When a significant event occurs, a program may call FlightRecorder.WriteTo to snapshot available trace data. The length of time and amount of data captured by a FlightRecorder may be configured within the FlightRecorderConfig.

sync

The new method on WaitGroup, WaitGroup.Go, makes the common pattern of creating and counting goroutines more convenient.

testing

The new methods T.Attr, B.Attr, and F.Attr emit an attribute to the test log. An attribute is an arbitrary key and value associated with a test.

For example, in a test named TestAttr, t.Attr("key", "value") emits:

=== ATTR  TestAttr key value

The new Output method of T, B and F provides an io.Writer that writes to the same test output stream as TB.Log, but omits the file and line number.

The AllocsPerRun function now panics if parallel tests are running. The result of AllocsPerRun is inherently flaky if other tests are running. The new panicking behavior helps catch such bugs.

testing/fstest

MapFS implements the new io/fs.ReadLinkFS interface. TestFS will verify the functionality of the io/fs.ReadLinkFS interface if implemented. TestFS will no longer follow symlinks to avoid unbounded recursion.

unicode

The new CategoryAliases map provides access to category alias names, such as “Letter” for “L”. The new categories Cn and LC define unassigned codepoints and cased letters, respectively. These have always been defined by Unicode but were inadvertently omitted in earlier versions of Go. The C category now includes Cn, meaning it has added all unassigned code points.

unique

The unique package now reclaims interned values more eagerly, more efficiently, and in parallel. As a consequence, applications using Make are now less likely to experience memory blow-up when lots of truly unique values are interned.

Values passed to Make containing Handles previously required multiple garbage collection cycles to collect, proportional to the depth of the chain of Handle values. Now, they are collected promptly in a single cycle, once unused.

Ports

Darwin

As announced in the Go 1.24 release notes, Go 1.25 requires macOS 12 Monterey or later; support for previous versions has been discontinued.

Windows

Go 1.25 is the last release that contains the broken 32-bit windows/arm port (GOOS=windows GOARCH=arm). It will be removed in Go 1.26.

Loong64

The linux/loong64 port now supports the race detector, gathering traceback information from C code using runtime.SetCgoTraceback, and linking cgo programs with the internal link mode.

RISC-V

The linux/riscv64 port now supports the plugin build mode.

The GORISCV64 environment variable now accepts a new value rva23u64, which selects the RVA23U64 user-mode application profile.