(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 -asanoption 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=0in 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 toolas needed. - A new
go.mod ignoredirective allows specifying directories that thegocommand should disregard when matching package patterns likeallor./…. These files are still included in module zip files. This feature is particularly beneficial for large monorepo projects. - The new
go doc -httpoption 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 -jsonoption prints JSON encodings ofruntime/debug.BuildInfostructures embedded in Go binary files. - The
gocommand 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
workpackage pattern matches all packages within the work (formerly main) modules, whether in single-module or workspace mode. - The
gocommand no longer automatically adds atoolchainline specifying the command’s current version when updatinggo.modorgo.workfiles.
- The
- Vet Analyzers: The
go vetcommand 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.Dialthat may not work with IPv6, suggestingnet.JoinHostPortas 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
GOMAXPROCShas 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,
GOMAXPROCSdefaults 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
GOMAXPROCSwould still be 8.The runtime periodically updates
GOMAXPROCSif the number of logical CPUs or the cgroup CPU bandwidth limit changes.These behaviors are automatically disabled if
GOMAXPROCSis manually set via the environment variable or a call toruntime.GOMAXPROCS. They can also be explicitly disabled withGODEBUGsettings:containermaxprocs=0andupdatemaxprocs=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=2as 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.modfile.
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=greenteagcat 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.FlightRecorderAPI 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.WriteToto 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
FlightRecordercan 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.AddCleanupare now executed concurrently and in parallel, making cleanups more viable for heavy use cases.Finalizer/Cleanup Diagnostics: A new
GODEBUG=checkfinalizers=1setting 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.Mutexvalues.
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.Openbefore 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.Pointerusage; thebisecttool with-compile=variablemakecan 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=Ncommand-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/synctestPackage:The
testing/synctestpackage, introduced experimentally in Go 1.24, has graduated to general availability in Go 1.25.It provides robust support for testing concurrent code. The
Testfunction runs a test function in an isolated “bubble” where time is virtualized, allowingtimepackage 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
Waitfunction 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
Runfunction from the Go 1.24 experiment is now deprecated in favor ofTest.
New Experimental
encoding/json/v2Package:Go 1.25 includes a new, experimental JSON implementation, accessible by setting
GOEXPERIMENT=jsonv2at build time.This is a major revision of the
encoding/jsonpackage, accompanied by theencoding/json/jsontextpackage 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/jsonpackage.It allows developers to implement custom marshalers and unmarshalers for arbitrary types using
MarshalToFuncandUnmarshalFromFunc, 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/v2is expected to continue evolving, and user feedback is highly encouraged for compatibility issues.
sync.WaitGroup.Go:- A new
WaitGroup.Gomethod 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.RootEnhancements:The
os.Roottype, used to limit filesystem operations to a specific directory, now supports several new methods mirroring existingospackage 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.DirFSandos.Root.FSnow implement the newio/fs.ReadLinkFSinterface, which providesReadLinkandLstatmethods for symbolic links.
reflect.TypeAssert:A new
reflect.TypeAssertfunction allows converting areflect.Valuedirectly to a Go value of a given type.This is similar to using a type assertion on the result of
Value.Interfacebut 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
testingPackage Improvements:The new
T.Attr,B.Attr, andF.Attrmethods 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-jsonflag 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
Outputmethod ofT,B, andFprovides anio.Writerthat writes to the same test output stream asTB.Logbut 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
AllocsPerRunfunction now panics if parallel tests are running. This change helps catch bugs where the results ofAllocsPerRunwould 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.GroupAttrsfunction creates a groupAttrfrom a slice ofAttrvalues, resolving an issue whereslog.Groupdid not accept[]slog.Attrdirectly.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.ClonerInterface: A newhash.Clonerinterface allows hash functions to return a copy of their current state. All standard libraryhash.Hashimplementations 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.AddFSnow supports symbolic links for filesystems implementingio/fs.ReadLinkFS.encoding/asn1:UnmarshalandUnmarshalWithParamsparseT61StringandBMPStringmore consistently, potentially rejecting previously accepted malformed encodings.cryptopackages: IntroduceMessageSignerinterface andSignMessagefunction. Significant performance boosts for signing incrypto/ecdsaandcrypto/ed25519(4x faster in FIPS 140-3 mode) andcrypto/rsakey 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:LookupMXandResolver.LookupMXnow return DNS names that resemble valid IP addresses, addressing a practical discrepancy where name servers sometimes return IP addresses despite RFC requirements. On Windows,ListenMulticastUDPsupports IPv6 addresses, and conversion betweenos.Fileand network connections is now possible.net/http: A newCrossOriginProtectiontype 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/armport (GOOS=windows GOARCH=arm). It is scheduled for removal in Go 1.26. - Loong64: The
linux/loong64port 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/riscv64port now supports thepluginbuild mode. Additionally, theGORISCV64environment 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/v2package 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.devand find Go code itself often more readable than external documentation due to its emphasis on simplicity and discouragement of deep abstractions. - The container-aware
GOMAXPROCSchange 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.Gomethod 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.LookupMXupdate (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/jsonbenchrepository 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