Skip to content
v5See what changed

A fast HTTP router for Go

Route net/http and fasthttp requests to plain handlers. Matching allocates nothing, params use the standard r.PathValue, and middleware costs nothing per request.

go get github.com/vardius/gorouter/v5
main.go
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello, %s!\n", r.PathValue("name"))
}
func main() {
router := gorouter.New()
router.GET("/hello/{name}", hello)
log.Fatal(http.ListenAndServe(":8080", router))
}
  • 0allocations to route a fasthttp request, params included
  • 7.2×faster than v4 behind three middleware on net/http
  • 16.9 nsto route a static path on fasthttp
  • 100%test coverage, plus fuzzing against a reference matcher

Features

Zero-allocation matching

Matching, middleware chains and finding no route allocate nothing. On fasthttp, neither do params or mounts.

Standard handlers

Any http.Handler, the usual func(http.Handler) http.Handler middleware, and params read with the standard r.PathValue.

Params and regexps

{id} matches a segment, {id:[0-9]+} only one the regexp matches. Literals win, and a failed branch falls back to the next.

Scoped middleware

Around the whole router, the routes below a path, or one method below a path. Composed once at registration.

Mounting

Hand a path to a sub-router or a file server. It sees paths relative to the mount, and mount params stay readable.

Correct by default

405 with an Allow header, automatic OPTIONS, custom methods, and clear panics for invalid patterns.

Performance

Faster than v4 behind middleware and on fasthttp

Section titled “Faster than v4 behind middleware and on fasthttp”

v5 composes middleware once at registration instead of on every request, and matches without allocating. A route behind three middleware went from 170 ns to 24 ns on net/http.

Time to route one request on net/http, lower is better
Show as a table
Time and allocations to route one request on net/http, v4 against v5
Scenariov4v5
Static route20.0 ns0 allocs19.9 ns0 allocs
Static, 5 segments28.5 ns0 allocs30.2 ns0 allocs
One param87.0 ns4 allocs93.6 ns2 allocs
Three params + regexp150.1 ns4 allocs148.5 ns2 allocs
Static + 3 middleware170.4 ns6 allocs23.8 ns0 allocs
One param + 3 middleware238.4 ns10 allocs100.8 ns2 allocs
404 Not Found20.0 ns0 allocs20.3 ns0 allocs
405 Method Not Allowed60.8 ns3 allocs55.8 ns2 allocs

Apple M4 Max, Go 1.27.0, median of 5 runs.

Upgrading

The patterns stay the same. The API around them is smaller: options instead of setters, the standard r.PathValue instead of a params type, and a fastrouter package for fasthttp.

v4
router := gorouter.New(logger)
router.GET("/hello/{name}", http.HandlerFunc(
func(w http.ResponseWriter, r *http.Request) {
params, _ := context.Parameters(r.Context())
fmt.Fprintf(w, "hello, %s!", params.Value("name"))
},
))
router.USE(http.MethodGet, "/admin", auth)
v5
router := gorouter.New(gorouter.WithMiddleware(logger))
router.GET("/hello/{name}",
func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "hello, %s!", r.PathValue("name"))
},
)
router.UseMethod(http.MethodGet, "/admin", auth)

Route your first request in five minutes

Install the module, register a handler, and serve. The guide walks through params, middleware and mounting.