NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
Go modules
Last release 11 days ago
18 Sep 2026
Release timing varies
gaps range from 8 days to 3 months
Nearly every release is documented
notes for 23 of 25 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
132 releases · first in 2021
One column per quarter.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
feat(middleware): add text/markdown, text/csv, text/vtt to default compressible types by @VojtechVitek in #1151
middleware.NewCompressor(level, "/*") never worked and silently compressed nothing. Instead of turning it into a compress-everything catch-all (as proposed in #868 and #1121), we decided to reject both "/" and "/*" at construction and panic. Compressing every response wastes CPU on already-compressed types (zip, jpeg, png), which is why the middleware keeps a curated default list. Users should pass explicit content types.Full Changelog: v5.3.1...v5.3.2
Nothing published for this version
Nothing published for this version
Honor Discard() in httpFancyWriter.ReadFrom by @DucMinhNe in #1110
Full Changelog: v5.3.0...v5.3.1
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
middleware.RealIP is deprecated in this PR with pointers to the new API.
@VojtechVitek submitted PR #967, which introduces middleware.ClientIP — a replacement for middleware.RealIP that closes the three open spoofing advisories:
RemoteAddr resolution (convto)middleware.RealIP (Saku0512, Critical / 9.3)It also addresses issues outlined at:
middleware.RealIP is deprecated in this PR with pointers to the new API.
The deprecation only adds a // Deprecated: doc comment; the function keeps working for backward compatibility.
RealIP has two unfixable design choices: it mutates r.RemoteAddr, and it tries to be a one-size-fits-all default by walking a hard-coded list of headers any client can supply. Per adam-p's "The perils of the 'real' client IP" (which calls chi out by name on this), there is no safe default — the user must pick their trust source explicitly.
Four middlewares, two accessors. Pick exactly one middleware based on your
infrastructure, read the result with one of the two accessors:
// One of the four. There is no safe default — pick exactly one.
func ClientIPFromHeader(trustedHeader string) func(http.Handler) http.Handler
func ClientIPFromXFF(trustedIPPrefixes ...string) func(http.Handler) http.Handler
func ClientIPFromXFFTrustedProxies(numTrustedProxies int) func(http.Handler) http.Handler
func ClientIPFromRemoteAddr(h http.Handler) http.Handler
// Read the result.
func GetClientIP(ctx context.Context) string // for logs, rate-limit keys
func GetClientIPAddr(ctx context.Context) netip.Addr // for typed work// Pick a single ClientIP middleware based on your deployment
// Cloudflare.
r.Use(middleware.ClientIPFromHeader("CF-Connecting-IP"))
// Nginx with ngx_http_realip_module.
r.Use(middleware.ClientIPFromHeader("X-Real-IP"))
// Apache with mod_remoteip.
r.Use(middleware.ClientIPFromHeader("X-Client-IP"))
// AWS CloudFront, or any proxy fleet with known CIDRs.
r.Use(middleware.ClientIPFromXFF(
"13.32.0.0/15", // CloudFront IPv4
"52.46.0.0/18", // CloudFront IPv4
"2600:9000::/28", // CloudFront IPv6
))
// Behind exactly 2 trusted proxies with dynamic IPs (autoscaling pools,
// ephemeral containers, dynamic CDN edges).
r.Use(middleware.ClientIPFromXFFTrustedProxies(2))
// Server directly on the public internet, no proxy in front.
r.Use(middleware.ClientIPFromRemoteAddr)And in your handler or downstream middleware:
clientIP := middleware.GetClientIP(r.Context())
// log it, use it as a rate-limit key, etc.Thanks to @adam-p, @c2h5oh, @rezmoss, @Saku0512, @convto, @Dirbaio, @jawnsy, @lrstanley, @mfridman, @n33pm, @pkieltyka for the prior discussions, detailed reviews, advisory reports, and test contributions that shaped this PR.
Full Changelog: v5.2.5...v5.3.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Bump minimum Go to 1.22 and use new features by @JRaspass in #1017
Full Changelog: v5.2.3...v5.2.5
Bump minimum Go to 1.22 and use new features by @JRaspass in #1017
Full Changelog: v5.2.3...v5.2.4
Nothing published for this version
Nothing published for this version
Add pathvalue example to README and implement PathValue handler. by @catatsuy in #985
Full Changelog: v5.2.2...v5.2.3
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Use strings.Cut in a few places by @JRaspass in #971
Full Changelog: v5.2.1...v5.2.2
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Starting this release, we will now support the four most recent major versions of Go. See #963 for related discussion.
Starting this release, we will now support the four most recent major versions of Go. See #963 for related discussion.
Full Changelog: v5.2.0...v5.2.1
Nothing published for this version
update credits section to link to goji license by @pkieltyka in #944
Find to Routes interface by @joeriddles in #872_examples/versions by @hongkuancn in #948Mux.Find not correctly handling nested routes by @joeriddles in #954Full Changelog: v5.1.0...v5.2.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Adds Discard() method to the middleware.WrapResponseWriter interface. This is technically an API breaking change. However after some discussion at #92…
Discard() method to the middleware.WrapResponseWriter interface. This is technically an API breaking change. However after some discussion at #926 (comment), we decided to move forward, and release as minor version, as we don't expect anyone to rely on this interface / implement it externally.Full Changelog: v5.0.14...v5.1.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →