chi

A lightweight, idiomatic Go HTTP router built entirely on net/http, for composing middleware and mounting REST APIs without a framework.

Library
Go
vv1.5.5
22,752stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
79/100Good
Development Activity80
Maintenance68
Community68
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture85
Code Quality88
Innovation60
Learning Curve85

chi is a small, composable router for building HTTP services in Go. Rather than wrapping or replacing the standard library, it builds directly on net/http, so every handler, middleware, and http.Handler from the wider Go ecosystem works with it unmodified. The router core is deliberately tiny (well under 1000 lines) and adds zero external dependencies, while still supporting named URL parameters, regexp-constrained segments, wildcard matching, and nested route groups.

What sets chi apart from a bare http.ServeMux is its support for structuring large APIs: Route() and Mount() let you compose independent sub-routers with their own middleware stacks, Group() scopes inline middleware to a subset of routes, and docgen can generate JSON or Markdown documentation directly from the routing tree. A companion middleware subpackage ships dozens of ready-made handlers — request IDs, structured logging, panic recovery, compression, rate limiting, and more — all written as ordinary func(http.Handler) http.Handler chains.

Under the hood, chi routes requests through a Patricic radix trie, giving predictable, allocation-conscious performance regardless of how many routes are registered. It has been running in production at Cloudflare, Heroku, 99Designs, and Pressly (chi’s originating team) for years, and the project maintains explicit compatibility with the four most recent Go major versions.

What You Get

  • A Mux implementing http.Handler, so it drops into any existing net/http server with zero adapter code
  • Named URL parameters ({userID}), regexp-constrained segments ({number:\d+}), and wildcard matching (/page/*)
  • Route(), Mount(), and Group() for composing large APIs out of independently middleware-scoped sub-routers
  • A middleware subpackage with dozens of stdlib-compatible handlers: request ID, structured logging, panic recovery, compression, timeouts, rate limiting, client-IP resolution
  • docgen-compatible route introspection via the Routes interface, for generating JSON/Markdown API docs straight from the routing tree
  • Zero external dependencies — pure Go standard library plus net/http

Common Use Cases

  • Building REST APIs that need explicit control over routing and middleware without adopting a full web framework
  • Migrating a net/http-based service off ServeMux once URL parameters, groups, or sub-router mounting become necessary
  • Composing microservices where each has an isolated middleware stack (auth, logging, rate limiting) mounted under a shared root router
  • Generating machine-readable route documentation for internal API catalogs via docgen
  • Building admin or versioned API surfaces (/admin, /v1, /v2) as separately mountable sub-routers with their own middleware

Under The Hood

Architecture chi’s core lives in three files: mux.go defines the Mux struct (an http.Handler wrapping a middleware chain and a routing tree), tree.go implements the radix trie that stores and matches URL patterns, and chi.go defines the public Router/Routes interfaces. A sync.Pool of Context objects (context.go) avoids per-request allocation for route params. Sub-routers created via Route() or attached via Mount() keep a parent pointer back to their owning Mux, so middleware scoping stays local to each mounted branch while route matching still traverses a single shared trie — a clean separation between routing (tree) and request processing (middleware chain) that means adding a new mounted service touches no existing router’s internals.

Tech Stack The module (github.com/go-chi/chi, migrated to github.com/go-chi/chi/v5 at HEAD) targets the four most recent Go major versions and declares zero runtime dependencies — everything is built on net/http, context, and sync. The middleware subpackage is a separate, optional import so consumers only pull in what they use. docgen and render exist as separate companion repositories rather than being bundled, keeping the core router’s dependency graph minimal.

Code Quality The project is heavily tested: mux_test.go (2100+ lines) and tree_test.go (700+ lines) exercise routing edge cases, wildcard precedence, and trie construction directly, alongside dedicated test files for most middleware handlers. CI (.github/workflows/ci.yml) runs the suite across four Go versions and both Linux and Windows on every push and PR. Error handling favors explicit http.Error calls in examples over panics, and the public API surface is small and consistently named (Get, Post, Route, Mount, Use), which keeps the exported interface easy to audit.

What Makes It Unique Unlike full-stack frameworks, chi’s entire value proposition is staying inside the net/http type system rather than replacing it — Mux is an http.Handler, middleware are func(http.Handler) http.Handler, and handlers are http.HandlerFunc. This makes it trivially composable with any other net/http-compatible package in the Go ecosystem, and lets teams mount independently-owned sub-routers as isolated units, a pattern that’s earned it long-standing adoption at companies running large, decomposed API surfaces.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search