TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/go-chi/chi/llms.txt
Use this file to discover all available pages before exploring further.
middleware package ships a comprehensive set of production-ready HTTP middleware handlers that compose cleanly with any chi router. Each handler follows the standard func(next http.Handler) http.Handler signature, so they slot into r.Use(...) or inline r.With(...).Get(...) chains with zero ceremony. Import the package once and mix in only what your application needs.
Logging & Observability
Logger
Logger
Logger delegates to middleware.DefaultLogger, which is a package-level variable of type func(next http.Handler) http.Handler. You can swap it for a custom LogFormatter at startup without changing your router wiring.RequestLogger
RequestLogger
LogFormatter. Use this when you need structured logging (JSON, zerolog, zap, etc.) instead of the default plaintext format.A value implementing
LogFormatter. Its NewLogEntry(r *http.Request) LogEntry method is called at the start of each request, and the returned LogEntry.Write(...) is deferred to run after the handler finishes.RequestID
RequestID
X-Request-Id header, that value is reused; otherwise a new ID of the form hostname/random-000001 is generated using an atomic counter.Retrieve the ID anywhere downstream with:Heartbeat
Heartbeat
200 OK with a "." body to all GET and HEAD requests at the given path. All other requests pass through unaffected. Place this above authentication middleware so load balancers and uptime monitors can reach it without credentials.The URL path to intercept, e.g.
"/ping" or "/healthz".Profiler
Profiler
net/http/pprof handlers and the expvar endpoint. Mount it under a protected path — never expose it on the public internet.The profiler registers these routes relative to its mount prefix:| Path | Handler |
|---|---|
/pprof/ | Index |
/pprof/cmdline | Cmdline |
/pprof/profile | CPU profile |
/pprof/symbol | Symbol lookup |
/pprof/trace | Execution trace |
/pprof/goroutine | Goroutine dump |
/pprof/threadcreate | Thread create |
/pprof/heap | Heap profile |
/pprof/block | Block profile |
/pprof/mutex | Mutex profile |
/pprof/allocs | Allocs profile |
/vars | expvar handler |
Resilience
Recoverer
Recoverer
HTTP 500 to the client. Prints the request ID (if available) alongside the stack. Re-panics http.ErrAbortHandler so connection abort semantics are preserved.ExampleTimeout
Timeout
HTTP 504 Gateway Timeout if the deadline was exceeded. Handlers must respect ctx.Done() for the cancellation to take effect — the middleware only cancels the context; it cannot forcibly terminate a handler that ignores it.Maximum time the handler is allowed to run before context cancellation. Example:
30 * time.Second.Throttle
Throttle
limit. Excess requests that exceed the ceiling receive HTTP 429 Too Many Requests. This is a server-wide concurrency ceiling, not a per-user rate limiter.Maximum number of in-flight requests allowed simultaneously. Must be
>= 1.ThrottleBacklog
ThrottleBacklog
Throttle with a waiting queue. Requests that exceed limit are held in the backlog (up to backlogLimit additional requests) and served as capacity frees up. Requests that wait longer than backlogTimeout receive HTTP 429.Maximum number of concurrently active requests.
Maximum number of requests that may queue while waiting for an active slot.
How long a queued request waits before being rejected with 429.
ThrottleWithOpts
ThrottleWithOpts
ThrottleOpts struct. Supports custom status codes and a Retry-After header callback.Maximum concurrent in-flight requests. Must be
>= 1.Size of the waiting queue (0 = no queue).
Maximum time a queued request waits. Defaults to 60 seconds.
HTTP status code returned when capacity is exceeded. Defaults to
429.Optional function that returns the
Retry-After duration. ctxDone is true when the client disconnected.Request & Content
AllowContentType
AllowContentType
Content-Type values on incoming requests. Requests with a body whose Content-Type does not match any entry in the list receive HTTP 415 Unsupported Media Type. Requests with an empty body (Content-Length: 0) bypass the check.One or more MIME types to permit, e.g.
"application/json", "text/xml". Matching is case-insensitive; charset parameters are stripped before comparison.AllowContentEncoding
AllowContentEncoding
Content-Encoding values. All encodings declared in the request header must appear in the allowed list, otherwise the request is rejected with HTTP 415. Empty-body requests are skipped.Encoding names to permit, e.g.
"gzip", "identity". Matching is case-insensitive.ContentCharset
ContentCharset
charset parameter within the Content-Type header matches one of the provided values. Responds with HTTP 415 on mismatch. Passing an empty string ("") as one of the charsets allows requests that carry no charset specification.Charset values to permit, e.g.
"utf-8", "iso-8859-1". Matching is case-insensitive.Compress
Compress
gzip or deflate based on the client’s Accept-Encoding header. Only responses whose Content-Type is in the allowed list are compressed. When no types are supplied, the default list covers common text and JavaScript types.Compression level as defined in the
compress/flate package. Use 5 as a sensible default, flate.BestSpeed for lower CPU cost, or flate.BestCompression for maximum ratio.MIME types to compress. Supports wildcard suffixes such as
"text/*". If omitted, the built-in list (text/html, text/css, text/plain, text/javascript, application/javascript, application/json, application/atom+xml, application/rss+xml, image/svg+xml) is used.Your handler must set
Content-Type before writing the response body, otherwise the middleware cannot determine whether to compress the output.SetHeader
SetHeader
The HTTP response header name, e.g.
"X-Content-Type-Options".The value to assign to the header.
Path & URL
StripSlashes
StripSlashes
r.URL.Path is modified in-place when no chi route context is present; otherwise rctx.RoutePath is updated.ExampleRedirectSlashes
RedirectSlashes
HTTP 301 Moved Permanently. Query strings are preserved in the redirect target.ExampleStripPrefix
StripPrefix
The URL path prefix to strip, e.g.
"/api/v1".CleanPath
CleanPath
/users//1 and ////users////1 are both normalised to /users/1. Operates on rctx.RoutePath when a chi route context is present.ExampleURLFormat
URLFormat
.json from /articles/1.json), stores it as a string under middleware.URLFormatCtxKey in the request context, and strips the suffix from the routing path so that a single route handles all formats.Retrieve the format string in a handler:GetHead
GetHead
HEAD requests to the corresponding GET handler when no explicit HEAD handler is registered. The response body is discarded by the HTTP stack as per the HTTP specification, but response headers (including Content-Length) are computed by the GET handler.ExamplePageRoute
PageRoute
GET request to the given handler at the middleware stack level, bypassing the router. Requests at any other path, or with any other method, pass through to the next handler.The URL path to intercept, matched case-insensitively against
r.URL.Path.The handler to invoke when the path matches a GET request.
PathRewrite
PathRewrite
old with new before passing the request to the next handler. Useful for adapting legacy path schemes or normalizing versioned prefixes.The substring to replace in
r.URL.Path.The replacement substring.
Security & Headers
BasicAuth
BasicAuth
crypto/subtle.ConstantTimeCompare to avoid timing attacks. Returns WWW-Authenticate and HTTP 401 on failure.The authentication realm displayed in the browser’s credential prompt.
A map of
username → password pairs. All values are stored in plaintext in memory, so keep the map small and use this middleware only for low-stakes protection or internal tooling.NoCache
NoCache
ETag, If-Modified-Since, If-Match, If-None-Match, If-Range, If-Unmodified-Since) to prevent conditional-GET short-circuits. Suitable for dynamic API routes, dashboards, and admin endpoints.Headers set on the response:| Header | Value |
|---|---|
Expires | Thu, 01 Jan 1970 00:00:00 UTC |
Cache-Control | no-cache, no-store, no-transform, must-revalidate, private, max-age=0 |
Pragma | no-cache |
X-Accel-Expires | 0 |
WithValue
WithValue
Context key. Use an unexported package-level type (e.g.
type ctxKey int) to avoid collisions.Value to store in the context.
Sunset
Sunset
Sunset and Deprecation headers to responses, signaling to API consumers that the route or API version will be retired. Optionally appends one or more Link header values pointing to successor documentation (per RFC 8594).The date and time when the endpoint will be retired. If the zero value is passed, no headers are added.
Optional
Link header values, e.g. "<https://api.example.com/v2>; rel=\"successor-version\"".Client IP
TheClientIPFrom* family of middleware provides secure, explicit mechanisms for determining the real client IP address. Each variant stores the resolved IP in the request context; read it with GetClientIP or GetClientIPAddr.
RealIP is deprecated and vulnerable to IP spoofing. Use the ClientIPFrom* middleware instead.ClientIPFromRemoteAddr
ClientIPFromRemoteAddr
RemoteAddr of the connection. This is the most trustworthy source when the server is exposed directly to the internet without any reverse proxy in front of it.IPv4-mapped IPv6 addresses (::ffff:a.b.c.d) are folded to plain IPv4 before storage.ExampleClientIPFromHeader
ClientIPFromHeader
X-Real-IP set by Nginx, CF-Connecting-IP set by Cloudflare). If the header carries multiple values, the last value is used — the one written by the hop closest to this server.The header name, e.g.
"X-Real-IP" or "CF-Connecting-IP". The value is canonicalized before lookup.ClientIPFromXFF
ClientIPFromXFF
X-Forwarded-For header chain from right to left, skipping IPs that fall within any of the provided trusted CIDR prefixes. The first non-trusted IP found is the client. If an unparseable entry is encountered mid-chain, the walk aborts and no IP is stored (fail-closed).CIDR prefixes of your trusted proxies. Panics at startup if any prefix is invalid. Pass no arguments to use the rightmost XFF entry (safe only when exactly one trusted hop sits in front of this server).
ClientIPFromXFFTrustedProxies
ClientIPFromXFFTrustedProxies
X-Forwarded-For by counting a fixed number of trusted proxy hops from the right. Returns the IP at position len(xff) - numTrustedProxies. Use when proxy IP ranges are dynamic (autoscaling, ephemeral containers) and enumerating CIDRs is impractical.Number of trusted reverse proxies between this server and the internet. Must be
>= 1. Panics at startup otherwise.GetClientIP / GetClientIPAddr
GetClientIP / GetClientIPAddr
ClientIPFrom* middleware.GetClientIPreturns the IP as a formatted string, or""if none was set.GetClientIPAddrreturns anetip.Addrzero value when not set; check with.IsValid()before use.
RealIP (Deprecated)
RealIP (Deprecated)
r.RemoteAddr to the value of True-Client-IP, X-Real-IP, or the leftmost entry of X-Forwarded-For (checked in that order).Utilities
New
New
http.Handler as a middleware. The wrapped handler executes and the request is passed to it; next is never called — the wrapped handler is the terminal handler in the chain. Useful for adapting existing http.Handler values (e.g. from third-party packages) for use with r.Use(...).The handler to execute as a middleware. It is called for every request;
next is not invoked.NewWrapResponseWriter
NewWrapResponseWriter
http.ResponseWriter with a proxy that captures the response status code and bytes written, and optionally tees the response body to a secondary writer. Automatically upgrades to implement http.Flusher, http.Hijacker, io.ReaderFrom, or http.Pusher when the underlying writer supports them.The response writer to wrap.
The HTTP major protocol version from
r.ProtoMajor (1 for HTTP/1.x, 2 for HTTP/2).WrapResponseWriter interfaceAdditional Helpers
RouteHeaders
RouteHeaders
HeaderRouter, a header-based middleware router. Chain .Route(header, match, middleware) calls to dispatch requests to different middleware stacks based on a request header value. Supports wildcard matching (*). Call .Handler as the final middleware in the chain.Additional methods on HeaderRouter:Route(header, match string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter— adds a route for a single match value or wildcard pattern.RouteAny(header string, match []string, middlewareHandler func(next http.Handler) http.Handler) HeaderRouter— adds a route that matches any one of several values.RouteDefault(handler func(next http.Handler) http.Handler) HeaderRouter— sets the fallback middleware when no other route matches.Handler(next http.Handler) http.Handler— the middleware entrypoint to pass tor.Use(...).