Key details

  1. Go 1.27 shipped August 19, 2026; Go team explained the change October 14.
  2. Applies to net/http.Transport HTTP/1 responses closed before full consumption.
  3. Asynchronous unread-body drain budget: up to 256 KiB or 50 milliseconds.
  4. Allows connection reuse if the remaining response reaches EOF within budget.
  5. No new public API required; standard response Body.Close() remains the recommended pattern.
  6. Go team example: 100 sequential HTTP/1 requests ~710 ms on 1.26 versus ~150 ms on 1.27, not an independent universal benchmark.
  7. HTTP/2 stream reuse is not subject to the same early-close problem.

What builders should take away

  1. If you operate status-only or small JSON HTTP/1 clients, compare connection reuse and latency before and after Go 1.27.
  2. Close response bodies promptly; manual draining just to save keep-alive connections may be unnecessary.
  3. Remove redundant unbounded drain helpers only after checking they serve no other application purpose.
  4. Benchmark on your own RTT, response sizes and protocols rather than extrapolating a fivefold improvement.
  5. Remember this optimisation is bounded; slow or large unread bodies can still lead to a new connection.

What changed

In an October 14, 2026 technical explanation, the Go team detailed an HTTP/1 client change already shipped with Go 1.27 on August 19. When an HTTP response body is closed before it has been fully consumed, net/http.Transport now tries to drain remaining bytes asynchronously for at most 50 milliseconds or 256 KiB. When the drain completes, the underlying TCP/TLS connection can be reused. Previously Go 1.26 and earlier usually abandoned that connection. The change requires no new API and does not alter HTTP/2 stream reuse.

Why it matters

Status-only API checks and JSON decoders that leave a trailing newline unread can silently force fresh HTTP/1 connections, adding network round trips, TLS work and latency. This implementation-level change makes common idiomatic Go code faster without requiring callers to invent fragile manual draining routines. It particularly helps sequential small-body API traffic, while very large or slow responses still favour closing rather than waiting to download unwanted data.

The subtle performance trap in Close

In HTTP/1, the next response on a connection cannot be parsed until the current response body's end is known. Calling resp.Body.Close() without reading to EOF used to make Go discard the connection. This affects callers interested only in HTTP status and programs that decode a JSON object but leave a newline or other trailing bytes unread. HTTP/2 multiplexing already handles separate streams differently, so the same manual draining advice does not apply there.

Go 1.27 drains within a strict budget

When an HTTP/1 response body is closed early, net/http.Transport can continue draining it asynchronously, stopping after 256 KiB or 50 ms. If it reaches EOF, the connection is reusable. If not, it can be discarded without forcing the caller to wait for an arbitrarily slow or large response. It skips work where reuse is impossible, such as a Connection: close response. The upstream implementation issue documents the semantics-preserving change.

A fivefold benchmark is illustrative, not a universal speed claim

The Go team reports that 100 sequential HTTP/1 status requests to index.golang.org took about 710 ms on Go 1.26 and 150 ms on Go 1.27 on the author's machine. The improvement comes from avoiding repeated connection establishment in that specific setup. It is not a general claim that every Go HTTP client or HTTP/2 application is five times faster. Response size, RTT, protocol negotiation, server keep-alive behaviour and request concurrency all matter.

Why manual draining was risky

A common workaround was to io.Copy to io.Discard before Close. Unbounded draining can waste bandwidth or hang on a slow server; developers needed byte limits, timeouts and concurrency management. Go's transport now centralises that bounded behaviour. Developers should generally close bodies promptly and avoid redundant custom drain helpers added solely to force HTTP/1 reuse.

Practical migration and checks

Teams moving from Go 1.26 to 1.27 should benchmark representative HTTP/1 traffic and inspect connection reuse with tracing rather than assuming the headline gain. Review existing io.Copy(io.Discard, body) helpers: some may now be unnecessary, while others may intentionally consume data for application reasons. Keep closing response bodies and do not confuse this change with security advisories or HTTP/2 optimisations.

What to watch next

  • Go net/http changes to the 256 KiB and 50 ms budgets in future versions.
  • Production benchmarks in high-RTT, API-heavy and proxy workloads.
  • Whether existing custom drain helpers can be safely simplified across popular Go libraries.

Still unclear

  • The Go-team latency figures are vendor-produced for a particular host and client environment.
  • No independent broad benchmark quantifies the benefit across production workloads.
  • Transport behaviour can evolve in future Go releases and is affected by server keep-alive policy.

Sources

Direct reading behind this dossier.

3 sources
Go Blog index
Go Project primary

Go 1.27 release date and chronology.

Discussion

Discussion is reader-contributed. Comments are not part of the BTN dossier or its editorial evidence.

0 visible comments

Join the discussion

Keep comments useful and relevant. Reader contributions may be moderated and are not BTN editorial evidence.

Sign in to comment