Fundamentals 11 min read

Why Go’s URL.Clone Method Was Rejected for 5 Years Yet Used Internally for 6

The article examines the five‑year rejection and six‑year hidden use of Go’s net/url Clone method, presents benchmark data showing it’s up to seven times faster than Parse‑String, recounts the proposal’s history, the internal cloneURL implementation, and explains when the new API is truly beneficial.

Radish, Keep Going!
Radish, Keep Going!
Radish, Keep Going!
Why Go’s URL.Clone Method Was Rejected for 5 Years Yet Used Internally for 6

Go 1.27.0 adds net/url.URL.Clone and net/url.Values.Clone. A quick benchmark on an Apple M5 (go1.27rc2 darwin/arm64, -benchmem -count 5) shows URL.Clone runs in 26.6 ns/op, about seven times faster than the common Parse(u.String()) approach (190.2 ns/op).

In 2020 a proposal (golang/go#41733) to add URL.Clone was rejected. The reviewer, Russ Cox, argued that shallow copying a struct is a common idiom and that URL was not special enough to merit a dedicated helper. The proposer could not provide usage statistics and eventually closed the issue, opting only to document that u2 := *u is safe.

Meanwhile, the Go team had been using an internal cloneURL function since 2019 in net/http/clone.go for Request.Clone and Transport.Clone. The function performs a shallow copy of the struct and deep‑copies the User field, mirroring the later public implementation. The source comment notes that the function is an internal detail but is accessed by third‑party packages via //go:linkname, e.g., github.com/searKing/golang.

In April 2025 Sean Liao reopened the proposal (golang/go#73450) and supplied concrete evidence: a GitHub code search found 21,200 occurrences of the shallow‑copy pattern url2 := *url1 versus only 3,300 occurrences of the round‑trip url.Parse(url1.String()). This usage data convinced the reviewers.

The proposal was marked likely accepted on 9 Feb 2026, accepted on 18 Feb 2026, and landed in CL 746800 and CL 746801. The final implementation uses the new Go 1.26 new(expr) syntax:

func (u *URL) Clone() *URL {
    if u == nil {
        return nil
    }
    uc := new(*u)
    if u.User != nil {
        uc.User = new(*u.User)
    }
    return uc
}

The Values.Clone method is similarly straightforward, allocating a new slice for each map entry and copying values with slices.Clone . The net/http package reuses the http.Header.Clone implementation via a type conversion. Before Clone existed, developers used three patterns:

Shallow copy with u2 := *u – safe for all fields except the pointer Userinfo, which caused uncertainty.

Round‑trip via url.Parse(u.String()) – safe but incurs encoding and parsing overhead and returns an error.

For Values, encode‑decode with url.ParseQuery(v.Encode()) – also incurs overhead and shares underlying slices.

Benchmarks on the same machine show:

BenchmarkValues_ManualDeepCopy-10    129.5 ns/op   512 B/op   6 allocs/op
BenchmarkValues_EncodeParseQuery-10 475.0 ns/op   808 B/op  16 allocs/op
BenchmarkValues_Clone-10            146.9 ns/op   512 B/op   6 allocs/op

These results confirm that URL.Clone is comparable in cost to the manual shallow copy while guaranteeing safety for Userinfo , and that Values.Clone is only about 13 % slower than a hand‑written deep copy but three times faster than the encode‑decode approach. Practical use cases include storing a base URL in configuration and cloning it per request to modify the path, or exposing a *url.URL from middleware/SDK without risking mutation of the original. In single‑threaded code, direct modification is safe, so Clone mainly addresses semantic uncertainty and performance, not mutability. The key lesson is that concrete usage data—"I checked"—can overturn long‑standing design decisions, as demonstrated by the six‑year hidden use of the method finally becoming an official API.

cover-wechat-net-url-clone
cover-wechat-net-url-clone
01-timeline-clone-six-years-v2
01-timeline-clone-six-years-v2
02-comparison-old-way-vs-clone
02-comparison-old-way-vs-clone
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

GoAPI designbenchmarkstandard librarynew(expr)URL.Clone
Radish, Keep Going!
Written by

Radish, Keep Going!

Personal sharing

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.