(medium subtitle)
Note: The core content was generated by an LLM, with human fact-checking and structural refinement.
Go 1.25 Release: Features and Innovations
The Go team officially announced the release of Go 1.25 in August 2025, arriving as scheduled, six months after Go 1.24. This latest version primarily focuses on significant enhancements to the toolchain, runtime, and standard libraries. As with previous releases, Go 1.25 upholds the Go 1 compatibility promise, ensuring that nearly all existing Go programs are expected to continue to compile and run without issues. The release underscores Go’s commitment to stability and pragmatic evolution, bringing “unseen benefits” to developers through underlying improvements.
Language Changes
Go 1.25 introduces no language changes that directly affect existing Go programs. This dedication to stability is a core reason for Go’s popularity in production environments. However, an internal “cleanup” occurred within the language specification: the notion of “core types” has been removed in favor of dedicated prose. While this change does not impact day-to-day coding, it simplifies the language specification and is considered a step towards paving the way for future evolutions of generics.
Tools
The Go 1.25 release significantly enhances the Go toolchain, boosting efficiency and reliability.
- Go Command Improvements:
- The
go build -asan
option now defaults to leak detection at program exit, reporting errors if C-allocated memory is unreferenced and not freed. This behavior can be disabled by settingASAN_OPTIONS=detect_leaks=0
in the environment. - The Go distribution will include fewer prebuilt tool binaries, with tools not invoked by build or test operations now being built and run by
go tool
as needed. - A new
go.mod ignore
directive allows specifying directories that thego
command should disregard when matching package patterns likeall
or./…
. These files are still included in module zip files. This feature is particularly beneficial for large monorepo projects. - The new
go doc -http
option launches a local documentation server, opening the requested object’s documentation in a browser window. This improves offline documentation access. - The new
go version -m -json
option prints JSON encodings ofruntime/debug.BuildInfo
structures embedded in Go binary files. - The
go
command now supports using a subdirectory of a repository as a module root, enabling more flexible module path resolution via the<meta name="go-import" content="root-path vcs repo-url subdir">
syntax. This addresses a long-standing challenge for monorepo managers and custom vanity imports. - A new
work
package pattern matches all packages within the work (formerly main) modules, whether in single-module or workspace mode. - The
go
command no longer automatically adds atoolchain
line specifying the command’s current version when updatinggo.mod
orgo.work
files.
- The
- Vet Analyzers: The
go vet
command includes two new analyzers:waitgroup
: Reports misplaced calls tosync.WaitGroup.Add
, such as calling it from inside a goroutine.hostport
: Detects uses offmt.Sprintf("%s:%d", host, port)
fornet.Dial
that may not work with IPv6, suggestingnet.JoinHostPort
as an alternative. These static checks help prevent common concurrency and networking errors.
Runtime
Go 1.25 features critical runtime improvements, including a container-aware GOMAXPROCS
and an experimental new garbage collector, among others.
Container-aware
GOMAXPROCS
:The default behavior of
GOMAXPROCS
has changed. Previously, it defaulted toruntime.NumCPU
, the number of logical CPUs available.On Linux, the runtime now considers the CPU bandwidth limit of the cgroup containing the process. If this limit (often corresponding to Kubernetes’ “CPU limit” option) is lower than the number of logical CPUs,
GOMAXPROCS
defaults to the lower limit. This makes Go applications more intelligent and efficient in containerized environments like Kubernetes, preventing resource waste or performance bottlenecks.For example, running a Go 1.25 program in a Docker container with CPU limits now respects those limits:
1
2
3
4docker run --cpus=4 golang:1.25-alpine go run /app/nproc.go
# Output:
# NumCPU: 8
# GOMAXPROCS: 4In contrast to Go 1.24 where
GOMAXPROCS
would still be 8.The runtime periodically updates
GOMAXPROCS
if the number of logical CPUs or the cgroup CPU bandwidth limit changes.These behaviors are automatically disabled if
GOMAXPROCS
is manually set via the environment variable or a call toruntime.GOMAXPROCS
. They can also be explicitly disabled withGODEBUG
settings:containermaxprocs=0
andupdatemaxprocs=0
.A new function,
runtime.SetDefaultGOMAXPROCS
, allows reverting to the runtime’s default value, enabling the new container-aware behavior even after a manual override.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19package main
import (
"fmt"
"runtime"
)
func main() {
// GOMAXPROCS=2 go run nproc.go (using environment variable)
fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))
// Using the manual setting
runtime.GOMAXPROCS(4)
fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))
// Back to the default value
runtime.SetDefaultGOMAXPROCS()
fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))
}Running with
GOMAXPROCS=2
as an env var:1
2
3GOMAXPROCS: 2
GOMAXPROCS: 4
GOMAXPROCS: 8 // Assuming 8 logical CPUs on the hostThis behavior only takes effect if the program uses Go version 1.25 or higher in its
go.mod
file.
New Experimental Garbage Collector (Green Tea GC):
- Go 1.25 introduces an experimental garbage collector, codenamed “Green Tea GC,” which can be enabled by setting
GOEXPERIMENT=greenteagc
at build time. - Designed to improve the performance of marking and scanning small objects through better locality and CPU scalability.
- The Go team anticipates a 10–40% reduction in garbage collection overhead in real-world programs that heavily use the GC. This is a significant performance benefit, especially for memory-intensive applications. For example, Josh Baker reported a 35% GC overhead reduction for his project Tile38 after enabling Green Tea GC.
- The design is expected to continue evolving, and user feedback is encouraged.
- Go 1.25 introduces an experimental garbage collector, codenamed “Green Tea GC,” which can be enabled by setting
Trace Flight Recorder:
- A new
runtime/trace.FlightRecorder
API provides a lightweight way to capture runtime execution traces. - It continuously records trace data into an in-memory ring buffer, tracking a sliding window of recent execution.
- When a significant event occurs, programs can call
FlightRecorder.WriteTo
to snapshot the last few seconds of the trace to a file. This approach produces much smaller traces, making it practical for debugging rare or intermittent issues in production environments. - The length of time and amount of data captured by a
FlightRecorder
can be configured.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44package main
import (
"fmt"
"math/rand"
"os"
"runtime/trace"
"time"
)
func main() {
// Configure the flight recorder to keep at least 5 seconds of trace data,
// with a maximum buffer size of 3MB. Both of these are hints, not strict limits.
cfg := trace.FlightRecorderConfig{
MinAge: 5 * time.Second,
MaxBytes: 3 << 20, // 3MB
}
// Create and start the flight recorder.
rec := trace.NewFlightRecorder(cfg)
rec.Start()
defer rec.Stop()
// Simulate some workload.
done := make(chan struct{})
go func() {
defer close(done)
const n = 1 << 20
var s []int
for range n {
s = append(s, rand.IntN(n))
}
fmt.Printf("done filling slice of %d elements\n", len(s))
}()
<-done
// Save the trace snapshot to a file.
file, _ := os.Create("/tmp/trace.out")
defer file.Close()
n, _ := rec.WriteTo(file)
fmt.Printf("wrote %dB to trace file\n", n)
fmt.Println("Use 'go tool trace /tmp/trace.out' to view the trace.")
}- A new
Unhandled Panic Output Change: The message for unhandled panics that were recovered and repanicked no longer repeats the panic value text. Instead, it now prints
[recovered, repanicked]
.VMA Names on Linux: On Linux systems with kernel support, the Go runtime now annotates anonymous memory mappings with their purpose (e.g.,
[anon: Go: heap]
). This can be disabled withGODEBUG=decoratemappings=0
.Concurrent Cleanups: Functions scheduled by
runtime.AddCleanup
are now executed concurrently and in parallel, making cleanups more viable for heavy use cases.Finalizer/Cleanup Diagnostics: A new
GODEBUG=checkfinalizers=1
setting assists in identifying common issues with finalizers and cleanups by running diagnostics and reporting queue lengths.Mutex Profile Improvement: The mutex profile for contention on runtime-internal locks now correctly points to the end of the critical section that caused the delay, matching the behavior for
sync.Mutex
values.
Compiler
The compiler in Go 1.25 includes important fixes and performance enhancements.
- Nil Pointer Bug Fix: This release fixes a compiler bug, introduced in Go 1.21, that could incorrectly delay nil pointer checks. Programs that previously executed successfully (but incorrectly) will now correctly panic with a nil-pointer exception.
For instance, code using the result of
os.Open
before checking the error will now behave as expected:1
2
3
4
5
6
7
8
9
10
11
12package main
import "os"
func main() {
f, err := os.Open("nonExistentFile")
name := f.Name() // This line will now correctly panic if f is nil
if err != nil {
return
}
println(name)
}The solution is to perform the non-nil error check immediately after the error-generating statement.
- DWARF5 Support: The compiler and linker now generate debug information using DWARF version 5. This reduces the space required for debugging information in Go binaries and decreases linking time, especially for large projects. DWARF 5 generation can be disabled using
GOEXPERIMENT=nodwarf5
. - Faster Slices: The compiler can now allocate the backing store for slices on the stack in more situations, leading to improved performance. This change might amplify issues with incorrect
unsafe.Pointer
usage; thebisect
tool with-compile=variablemake
can help identify problems. All new stack allocations can also be turned off with-gcflags=all=-d=variablemakehash=n
.
Linker
The linker in Go 1.25 gains a new command-line option:
- The linker now accepts a
-funcalign=N
command-line option, which specifies the alignment of function entries. The default value remains platform-dependent and unchanged in this release.
Standard Library
Go 1.25 brings a comprehensive list of standard library improvements, including new packages, experimental features, and minor enhancements across various modules.
New
testing/synctest
Package:The
testing/synctest
package, introduced experimentally in Go 1.24, has graduated to general availability in Go 1.25.It provides robust support for testing concurrent code. The
Test
function runs a test function in an isolated “bubble” where time is virtualized, allowingtime
package functions to operate on a fake clock. The clock advances instantaneously if all goroutines in the bubble are blocked. This enables testing timeout scenarios without actual delays.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33package main
import (
"errors"
"fmt"
"testing"
"time"
"golang.org/x/sync/synctest" // Renamed from "sync/synctest" in source for illustration
)
// Read reads a value from the input channel and returns it.
// Timeouts after 60 seconds.
func Read(in chan int) (int, error) {
select {
case v := <-in:
return v, nil
case <-time.After(60 * time.Second):
return 0, errors.New("timeout")
}
}
func TestReadTimeout(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
ch := make(chan int)
_, err := Read(ch)
if err == nil {
t.Fatal("expected timeout error, got nil")
}
fmt.Println("TestReadTimeout PASS") // Illustrative print
})
}
// This test would pass instantly without waiting 60 secondsThe
Wait
function waits for all goroutines in the current bubble to block before resuming execution.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package main
import (
"fmt"
"testing"
"time"
"golang.org/x/sync/synctest"
)
func TestWait(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
var innerStarted bool
done := make(chan struct{})
go func() {
innerStarted = true
time.Sleep(time.Second)
close(done)
}()
// Wait for the inner goroutine to block on time.Sleep.
synctest.Wait()
// innerStarted is guaranteed to be true here.
fmt.Printf("inner started: %v\n", innerStarted)
<-done
})
}
// Output: inner started: trueThe
Run
function from the Go 1.24 experiment is now deprecated in favor ofTest
.
New Experimental
encoding/json/v2
Package:Go 1.25 includes a new, experimental JSON implementation, accessible by setting
GOEXPERIMENT=jsonv2
at build time.This is a major revision of the
encoding/json
package, accompanied by theencoding/json/jsontext
package for lower-level JSON syntax processing.The new implementation offers substantially faster decoding performance compared to the existing one, with encoding performance remaining at parity in many scenarios. This addresses long-standing performance concerns with the
encoding/json
package.It allows developers to implement custom marshalers and unmarshalers for arbitrary types using
MarshalToFunc
andUnmarshalFromFunc
, providing greater control over JSON serialization.For example, marshaling boolean values (
true
/false
) and “boolean-like” strings (on
/off
) to custom symbols:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43package main
import (
"fmt"
"encoding/json"
"github.com/go-json-experiment/jsonv2" // Updated import for v2
"github.com/go-json-experiment/jsonv2/jsontext"
)
func main() {
// Marshals boolean values to ✓ or ✗.
boolMarshaler := jsonv2.MarshalToFunc(
func(enc *jsontext.Encoder, val bool) error {
if val {
return enc.WriteToken(jsontext.String("✓"))
}
return enc.WriteToken(jsontext.String("✗"))
},
)
// Marshals boolean-like strings to ✓ or ✗.
strMarshaler := jsonv2.MarshalToFunc(
func(enc *jsontext.Encoder, val string) error {
if val == "on" || val == "true" {
return enc.WriteToken(jsontext.String("✓"))
}
if val == "off" || val == "false" {
return enc.WriteToken(jsontext.String("✗"))
}
// SkipFunc tells Go to skip the current marshaler and move to the next.
return jsonv2.SkipFunc
},
)
// Combine custom marshalers with JoinMarshalers.
marshalers := jsonv2.JoinMarshalers(boolMarshaler, strMarshaler)
// Marshal some values.
vals := []any{true, "off", "hello"}
data, err := jsonv2.Marshal(vals, jsonv2.WithMarshalers(marshalers))
fmt.Println(string(data), err)
}
// Output: ["✓","✗","hello"] <nil>The design of
encoding/json/v2
is expected to continue evolving, and user feedback is highly encouraged for compatibility issues.
sync.WaitGroup.Go
:- A new
WaitGroup.Go
method makes the common pattern of creating and counting goroutines more convenient. - It automatically increments the wait group counter, runs a function in a goroutine, and decrements the counter when the function is done, eliminating the need for boilerplate
wg.Add(1)
anddefer wg.Done()
calls.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Go(func() {
fmt.Println("go is awesome")
})
wg.Go(func() {
fmt.Println("cats are cute")
})
wg.Wait()
fmt.Println("done")
}
/*
Output (order may vary for "go is awesome" and "cats are cute"):
cats are cute
go is awesome
done
*/- A new
os.Root
Enhancements:The
os.Root
type, used to limit filesystem operations to a specific directory, now supports several new methods mirroring existingos
package functions. This makes working with files much safer.New methods include
Chmod
,Chown
,Chtimes
,Lchown
,Link
,MkdirAll
,ReadFile
,Readlink
,RemoveAll
,Rename
,Symlink
, andWriteFile
.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58package main
import (
"fmt"
"os"
"syscall"
"time"
)
func main() {
// This example assumes a "data" directory exists and has a "01.txt" file.
// In a real scenario, you'd handle directory/file creation and errors.
// For demonstration, these files might need to be created manually or programmatically.
// Example: Chmod
root, _ := os.OpenRoot("data")
defer root.Close() // Ensure the root is closed
// Create a dummy file for Chmod example if it doesn't exist
root.WriteFile("01.txt", []byte("hello"), 0644)
root.Chmod("01.txt", 0600)
finfo, _ := root.Stat("01.txt")
fmt.Println("Chmod:", finfo.Mode().Perm()) // Output: -rw-------
// Example: Chown (requires appropriate permissions and user IDs)
// root.Chown("01.txt", 1000, 1000)
// finfo, _ = root.Stat("01.txt")
// stat := finfo.Sys().(*syscall.Stat_t)
// fmt.Printf("Chown: uid=%d, gid=%d\n", stat.Uid, stat.Gid)
// Example: MkdirAll
const dname = "path/to/secret"
root.MkdirAll(dname, 0750)
finfo, _ = root.Stat(dname)
fmt.Printf("MkdirAll: %s %s\n", dname, finfo.Mode()) // Output: path/to/secret drwxr-x---
// Example: Symlink & Readlink
const lname = "symlink.txt"
root.Symlink("01.txt", lname)
lpath, _ := root.Readlink(lname)
fmt.Printf("Symlink/Readlink: %s -> %s\n", lname, lpath) // Output: symlink.txt -> 01.txt
// Example: WriteFile & ReadFile
const fname = "go.txt"
root.WriteFile(fname, []byte("go is awesome"), 0644)
content, _ := root.ReadFile(fname)
fmt.Printf("WriteFile/ReadFile: %s: %s\n", fname, content) // Output: go.txt: go is awesome
// Example: Rename
const oldname = "01.txt"
const newname = "go_old.txt"
root.Rename(oldname, newname)
_, err := root.Stat(oldname)
fmt.Printf("Rename (old name error): %v\n", err) // Output: stat data/01.txt: no such file or directory
finfo, _ = root.Stat(newname)
fmt.Printf("Rename (new name): %s\n", finfo.Name()) // Output: go_old.txt
}Filesystems returned by
os.DirFS
andos.Root.FS
now implement the newio/fs.ReadLinkFS
interface, which providesReadLink
andLstat
methods for symbolic links.
reflect.TypeAssert
:A new
reflect.TypeAssert
function allows converting areflect.Value
directly to a Go value of a given type.This is similar to using a type assertion on the result of
Value.Interface
but avoids unnecessary memory allocations by not boxing the value in an interface.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
}
func main() {
alice := &Person{"Alice", 25}
// Given a reflection Value...
aliceVal := reflect.ValueOf(alice).Elem()
// ...convert it back to the Person type using TypeAssert.
person, _ := reflect.TypeAssert[Person](aliceVal)
fmt.Printf("Name: %s, Age: %d\n", person.Name, person.Age)
}
// Output: Name: Alice, Age: 25
testing
Package Improvements:The new
T.Attr
,B.Attr
, andF.Attr
methods allow emitting arbitrary key-value attributes to the test log. This is useful for associating metadata like issue links or descriptions with test results, especially when using the-json
flag for automated processing.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18package main
import "testing"
func TestAttrs(t *testing.T) {
t.Attr("issue", "demo-1234")
t.Attr("description", "Testing for the impossible")
if 21*2 != 42 {
t.Fatal("What in the world happened to math?")
}
}
/*
Output (partially):
=== RUN TestAttrs
=== ATTR TestAttrs issue demo-1234
=== ATTR TestAttrs description Testing for the impossible
--- PASS: TestAttrs (0.00s)
*/The new
Output
method ofT
,B
, andF
provides anio.Writer
that writes to the same test output stream asTB.Log
but without file and line numbers. This is handy for directing application logs into the test output.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21package main
import (
"log/slog"
"testing"
)
func TestLog(t *testing.T) {
t.Log("test message 1")
t.Log("test message 2")
appLog := slog.New(slog.NewTextHandler(t.Output(), nil))
appLog.Info("app message")
}
/*
Output (partially):
=== RUN TestLog
main_test.go:12: test message 1
main_test.go:13: test message 2
time=... level=INFO msg="app message"
--- PASS: TestLog (0.00s)
*/The
AllocsPerRun
function now panics if parallel tests are running. This change helps catch bugs where the results ofAllocsPerRun
would be flaky due to concurrent test execution.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package main
import "testing"
func TestAllocs(t *testing.T) {
t.Parallel() // Enables parallel execution
allocs := testing.AllocsPerRun(100, func() {
var s []int
// Do some allocations.
for i := range 1024 {
s = append(s, i)
}
})
t.Log("Allocations per run:", allocs) // This will now panic in Go 1.25
}
/*
Output (Go 1.25):
=== RUN TestAllocs
=== PAUSE TestAllocs
=== CONT TestAllocs
--- FAIL: TestAllocs (0.00s)
panic: testing: AllocsPerRun called during parallel test [recovered, repanicked]
*/
log/slog.GroupAttrs
: The newslog.GroupAttrs
function creates a groupAttr
from a slice ofAttr
values, resolving an issue whereslog.Group
did not accept[]slog.Attr
directly.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package main
import (
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
// Before GroupAttrs, this would cause a compilation error:
// attrs := []slog.Attr{
// slog.Int("value", 1000),
// slog.String("currency", "USD"),
// }
// logger.Info("deposit", slog.Bool("ok", true), slog.Group("amount", attrs...),)
// With slog.GroupAttrs
attrs := []slog.Attr{
slog.Int("value", 1000),
slog.String("currency", "USD"),
}
logger.Info("deposit", slog.Bool("ok", true), slog.GroupAttrs("amount", attrs...),)
}
// Output: time=... level=INFO msg=deposit ok=true amount.value=1000 amount.currency=USDhash.Cloner
Interface: A newhash.Cloner
interface allows hash functions to return a copy of their current state. All standard libraryhash.Hash
implementations now implementCloner
, including MD5, SHA-1, SHA-3, FNV-1, CRC-64, and others.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28package main
import (
"fmt"
"reflect"
"golang.org/x/crypto/sha3" // Example with sha3
)
func main() {
h1 := sha3.New256()
h1.Write([]byte("hello"))
clone, _ := h1.Clone() // Clone the current state of h1
h2 := clone.(*sha3.SHA3)
// h2 has the same state as h1. Further writes to each will result in the same hash.
h1.Write([]byte("world"))
h2.Write([]byte("world"))
fmt.Printf("h1: %x\n", h1.Sum(nil))
fmt.Printf("h2: %x\n", h2.Sum(nil))
fmt.Printf("h1 == h2: %t\n", reflect.DeepEqual(h1.Sum(nil), h2.Sum(nil)))
}
// Output:
// h1: ... (same hash)
// h2: ... (same hash)
// h1 == h2: trueOther Notable Changes:
archive/tar
:Writer.AddFS
now supports symbolic links for filesystems implementingio/fs.ReadLinkFS
.encoding/asn1
:Unmarshal
andUnmarshalWithParams
parseT61String
andBMPString
more consistently, potentially rejecting previously accepted malformed encodings.crypto
packages: IntroduceMessageSigner
interface andSignMessage
function. Significant performance boosts for signing incrypto/ecdsa
andcrypto/ed25519
(4x faster in FIPS 140-3 mode) andcrypto/rsa
key generation (3x faster). SHA-1 hashing is 2x faster on amd64 with SHA-NI instructions. SHA3 hashing is 2x faster on Apple M processors.crypto/tls
: Stricter adherence to specifications, disallowing SHA-1 signature algorithms in TLS 1.2 by default (re-enableable viaGODEBUG=tlssha1=1
). TLS servers now prefer the highest supported protocol version.net
:LookupMX
andResolver.LookupMX
now return DNS names that resemble valid IP addresses, addressing a practical discrepancy where name servers sometimes return IP addresses despite RFC requirements. On Windows,ListenMulticastUDP
supports IPv6 addresses, and conversion betweenos.File
and network connections is now possible.net/http
: A newCrossOriginProtection
type implements protections against Cross-Site Request Forgery (CSRF) using modern browser Fetch metadata, without requiring tokens or cookies.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40package main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /get", func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "ok\n")
})
mux.HandleFunc("POST /post", func(w http.ResponseWriter, req *http.Request) {
io.WriteString(w, "ok\n")
})
antiCSRF := http.NewCrossOriginProtection()
antiCSRF.AddTrustedOrigin("https://example.com")
antiCSRF.AddTrustedOrigin("https://*.example.com")
srv := http.Server{
Addr: ":8080",
Handler: antiCSRF.Handler(mux),
}
log.Fatal(srv.ListenAndServe())
// To test, run this Go program and then use curl in another terminal:
// curl --data "ok" -H "sec-fetch-site:same-origin" localhost:8080/post
// Output: ok
// curl --data "ok" -H "sec-fetch-site:cross-site" localhost:8080/post
// Output: cross-origin request detected from Sec-Fetch-Site header
// curl --data "ok" -H "origin:https://evil.com" -H "host:antonz.org" localhost:8080/post
// Output: cross-origin request detected, and/or browser is out of date: Sec-Fetch-Site is missing, and Origin does not match Host
// curl --data "ok" -H "origin:https://example.com" -H "host:antonz.org" localhost:8080/post
// Output: ok
// curl -H "origin:https://evil.com" localhost:8080/get
// Output: ok
}unique
: The unique package now reclaims interned values more eagerly, efficiently, and in parallel, reducing memory consumption for applications that intern many unique values.
Ports
Go 1.25 includes updates and changes to supported platforms:
- Darwin: Go 1.25 requires macOS 12 Monterey or later. Support for previous versions has been discontinued, as announced in the Go 1.24 release notes.
- Windows: Go 1.25 is the last release that includes the 32-bit
windows/arm
port (GOOS=windows GOARCH=arm
). It is scheduled for removal in Go 1.26. - Loong64: The
linux/loong64
port now supports the race detector, gathers traceback information from C code usingruntime.SetCgoTraceback
, and can link cgo programs with the internal link mode. - RISC-V: The
linux/riscv64
port now supports theplugin
build mode. Additionally, theGORISCV64
environment variable accepts a new value,rva23u64
, which selects the RVA23U64 user-mode application profile.
Community Reception
The Go 1.25 release has been met with a generally positive reception from the community, highlighting key features and broader aspects of the language.
- The new
encoding/json/v2
package is a standout feature, drawing significant attention and excitement. Developers anticipate performance improvements and the ability to implement custom marshalers for external types, addressing a long-standing pain point in Go’s JSON handling. The experimental nature and expected evolution of the API are noted, with calls for users to test and provide feedback. - Go’s stability and maintainability continue to be highly valued. Many developers praise the language for its consistent backward compatibility, allowing non-trivial source code to build and run even after a decade without issues. This “killer feature” is particularly appreciated by sysadmin/ops focused professionals for its static binaries and predictable resource profiles.
- Discussion around Go’s documentation and ecosystem reveals varied experiences. While some find third-party module documentation lacking or outdated, others appreciate the consistent documentation on
pkg.go.dev
and find Go code itself often more readable than external documentation due to its emphasis on simplicity and discouragement of deep abstractions. - The container-aware
GOMAXPROCS
change is seen as one of the most impactful improvements, particularly for applications deployed in Kubernetes and Docker environments, leading to more intelligent and efficient CPU resource usage. - The
sync.WaitGroup.Go
method is widely welcomed for simplifying concurrent programming boilerplate, improving code readability and reducing common errors. - The experimental Green Tea GC is also eagerly anticipated, with expectations of significant overhead reduction in garbage collection for real-world programs.
- Minor changes, such as stricter TLS handling and the
net.LookupMX
update (which prioritizes “reality compliance” over strict RFC adherence to handle real-world DNS server behaviors), are generally well-received. - The overall sentiment is that Go 1.25 is a “great release”, emphasizing pragmatism over “flashy syntax sugar,” focusing on fundamental improvements that provide “invisible benefits” to developers, allowing them to concentrate on business logic while Go handles complex system optimization.
Links to quoted articles and resources:
- Official Go 1.25 Release Notes: https://go.dev/doc/go1.25
- GitHub issue for new experimental GC (Green Tea GC): https://github.com/golang/go/issues/73581
- GitHub proposal issue for
encoding/json/v2
: https://github.com/golang/go/issues/63397 go-json-experiment/jsonbench
repository for detailed performance analysis: https://github.com/go-json-experiment/jsonbench- “How we tracked down a Go 1.24 memory regression” (Datadog blog): https://www.datadoghq.com/blog/engineering/go-memory-regress/
- GitHub issue for memory regression fix (Go 1.25): https://github.com/golang/go/issues/72991
- Anton Zhiyanov’s interactive tour for Go 1.25 features: https://antonz.org/go-1-25/
- Phoronix article “Go 1.25 Released With Experimental GC Yielding 10~40% Overhead Reduction”: https://www.phoronix.com/news/Go-1.25-Released
More
Recent Articles:
- Vibe Specs: Spec-First AI Development on Medium on Website
- Error Handling in Go vs.Zig on Medium on Website
Random Article:
More Series Articles about You Should Know In Golang:
https://wesley-wei.medium.com/list/you-should-know-in-golang-e9491363cd9a
And I’m Wesley, delighted to share knowledge from the world of programming.
Don’t forget to follow me for more informative content, or feel free to share this with others who may also find it beneficial. It would be a great help to me.
Give me some free applauds, highlights, or replies, and I’ll pay attention to those reactions, which will determine whether I continue to post this type of article.
See you in the next article. 👋
中文文章: https://programmerscareer.com/zh-cn/go-1-25/
Author: Medium,LinkedIn,Twitter
Note: Originally written at https://programmerscareer.com/go-1-25/ at 2025-08-17 10:33.
Copyright: BY-NC-ND 3.0
Comments