Better HTTP/1 connection reuse in Go 1.27

279 points · 45 comments on HN · read original →

Points and comments are a snapshot, not live.

Go 1.27 automatically drains unread HTTP/1 response bodies to reuse connections, boosting performance up to 5x.

Go's net/http historically abandoned HTTP/1 connections when response bodies weren't fully read, forcing costly new TCP/TLS handshakes. A benchmark calling getStatus 100 times against index.golang.org took ~710ms on Go 1.26 vs ~150ms on Go 1.27. Starting in Go 1.27, Transport asynchronously drains unread HTTP/1 bodies up to 50ms or 256KB, skipping drain for Connection: close. Users should simply call resp.Body.Close().

Earlier workarounds required manual draining with io.CopyN and timeouts, often done incorrectly. The fix does not affect HTTP/2, which already multiplexes streams. Go recommends keeping code simple and letting net/http handle connection reuse.

What commenters are saying

Commenters broadly welcome the change, with several noting they can retire custom drain helpers copied across projects for years. A top comment points out that even reading the body with json.Decoder can leave trailing newlines unread, breaking reuse-a subtle edge case the new auto-drain addresses. Some discuss the tradeoff: automatically draining up to 50ms means canceled requests still incur a small cost, but most see this as acceptable. A few ask how to force immediate close if needed, noting the behavior is now documented in net/http.Client.Do.