gziphandler
Go middleware that transparently gzip-compresses HTTP responses for clients that support it
Repository Health
Technical Analysis
gziphandler is a lightweight Go middleware that wraps any http.Handler to transparently gzip-compress response bodies for clients that send an Accept-Encoding: gzip header. Originally built by The New York Times, it’s meant for services that can’t or don’t want to rely on a reverse proxy like nginx or Varnish to handle compression at that layer.
Under the hood it pools gzip.Writer instances per compression level via sync.Pool to avoid repeated allocation overhead, buffers the first bytes of a response to detect content type before deciding whether to compress, and passes responses through untouched when a Content-Encoding is already set or a Content-Length falls under the configured minimum size. Functional options let callers pick a compression level, a minimum size threshold, and a content-type allowlist, and the response writer correctly implements http.Flusher and http.Hijacker so it composes with other middleware in a standard net/http stack.
What You Get
- A GzipHandler(http.Handler) http.Handler function for one-line response compression
- Configurable compression level via NewGzipLevelHandler and the CompressionLevel option
- A MinSize option to skip compressing small responses that wouldn’t benefit
- A ContentTypes option to restrict compression to specific MIME types
- Pooled gzip.Writer reuse via sync.Pool for lower allocation overhead under load
Common Use Cases
- Compressing JSON API responses served directly from a Go HTTP server with no reverse proxy in front
- Wrapping existing http.Handler-based routers (net/http, gorilla/mux, chi) with gzip support
- Serving static or templated HTML pages more efficiently to browsers that advertise gzip support
- Reducing bandwidth for services running on container or serverless platforms without a dedicated compressing proxy
Under The Hood
Architecture The library is a flat, single-purpose middleware built around one functional core, GzipHandlerWithOpts (in gzip.go), which returns a closure wrapping any http.Handler. Per-request state is threaded through the GzipResponseWriter struct (buf, code, ignore, gw, minSize, contentTypes), whose Write method buffers early bytes to sniff content-type and defers the gzip-vs-passthrough decision until minSize bytes are buffered or a Content-Length is known, then lazily calls startGzip or startPlain. A separate build-tagged file, gzip_go18.go, adds a Push method for HTTP/2 server push on Go 1.8+. Close, Flush, and Hijack forward to the underlying ResponseWriter, so GzipResponseWriter implements io.Writer, http.Flusher, http.Hijacker, and http.CloseNotifier and composes transparently into any http.Handler chain; there’s no dependency injection or multi-layer structure to speak of, and changing the shared struct’s fields would ripple through every method built on it.
Tech Stack
Written in Go (go.mod targets go 1.11) with a single external dependency, github.com/stretchr/testify v1.3.0, used only in tests. Runtime code is stdlib-only (compress/gzip, net/http, sync, mime, bufio, net) — there’s no web framework, ORM, or database involved, since this is a middleware meant to plug into any net/http-compatible router. CI runs via Travis (.travis.yml), executing go test -race -v against both go 1.x and tip with GO111MODULE=on; there’s no separate build step since the package is consumed as a library, not deployed standalone.
Code Quality
Tests live in gzip_test.go (673 lines) and the build-tagged gzip_go18_test.go (70 lines), using stretchr/testify assertions plus table-driven cases and a benchmark fixture in testdata/benchmark.json. Error handling is explicit: config.validate() rejects invalid compression levels and negative minSize with descriptive errors, MustNewGzipLevelHandler panics for callers who prefer a non-error API, and Hijack/Push return standard sentinel-style errors when the underlying ResponseWriter doesn’t support them. Naming follows Go conventions throughout (exported functional options like MinSize, CompressionLevel, ContentTypes; unexported helpers in lowerCamelCase). There’s no dedicated linter configuration — quality enforcement leans on go test -race across two Go versions in CI rather than a separate lint step.
What Makes It Unique The standout technique is the array of per-compression-level sync.Pool instances (gzipWriterPools, indexed via poolIndex) that reuse gzip.Writer objects across requests instead of allocating a fresh one each time, paired with a buffered-write scheme that defers the compress-or-passthrough decision until enough bytes are seen — letting it skip responses that are already encoded, too small to be worth compressing, or excluded by content type without a separate sniffing pass. These are patterns large-scale Go HTTP servers commonly reach for to cut GC churn, executed cleanly, rather than anything algorithmically novel.
Used by 2 apps in this directory
Rill
Analytics · Data Engineering
The fastest BI tool for humans and agents — define metrics, models, and dashboards as code and query them instantly on ClickHouse or DuckDB.
Stormkit
Devops · Hosting Control Panel
Self-hostable platform for deploying and hosting modern web apps with automated CI/CD, custom domains, and a built-in serverless runtime — a true open-source alternative to Vercel and Netlify.