On this page

Migration Guide

This guide shows how to migrate an existing Go application to MuxMaster from three common routers: gorilla/mux, chi, and httprouter.

MuxMaster implements http.Handler and uses the same http.HandlerFunc signature as the standard library. Most migrations consist of replacing route registration calls — no handler code changes are required.

Table of Contents


From gorilla/mux

gorilla/mux is archived and no longer maintained. MuxMaster provides a compatible API with dramatically better performance.

Route registration

// gorilla/mux
r := mux.NewRouter()
r.HandleFunc("/users", listUsers).Methods("GET")
r.HandleFunc("/users", createUser).Methods("POST")
r.HandleFunc("/users/{id}", getUser).Methods("GET")
r.HandleFunc("/users/{id}", updateUser).Methods("PUT")
r.HandleFunc("/users/{id}", deleteUser).Methods("DELETE")
// MuxMaster
mux := muxmaster.New()
mux.GET("/users", listUsers)
mux.POST("/users", createUser)
mux.GET("/users/:id", getUser)
mux.PUT("/users/:id", updateUser)
mux.DELETE("/users/:id", deleteUser)

Path parameters

// gorilla/mux
id := mux.Vars(r)["id"]
// MuxMaster
id := muxmaster.PathParam(r, "id")
// or
id := muxmaster.ParamsFromContext(r.Context()).Get("id")

Regex-constrained parameters

gorilla/mux regex syntax and MuxMaster syntax differ slightly:

// gorilla/mux — regex inside curly braces after colon
r.HandleFunc("/users/{id:[0-9]+}", getUser)

// MuxMaster — same syntax, compatible
mux.GET("/users/{id:[0-9]+}", getUser)

Subrouters

// gorilla/mux
api := r.PathPrefix("/api/v1").Subrouter()
api.Use(requireAPIKey)
api.HandleFunc("/users", listUsers).Methods("GET")
// MuxMaster
api := mux.Group("/api/v1")
api.Use(requireAPIKey)
api.GET("/users", listUsers)

Middleware

// gorilla/mux
r.Use(loggingMiddleware)
// MuxMaster — identical
mux.Use(loggingMiddleware)

Starting the server

// gorilla/mux
http.ListenAndServe(":8080", r)

// MuxMaster — identical
http.ListenAndServe(":8080", mux)

From chi

chi and MuxMaster share a very similar API. Most migrations require minimal changes.

Route registration

// chi
r := chi.NewRouter()
r.Get("/users", listUsers)
r.Post("/users", createUser)
r.Get("/users/{id}", getUser)
r.Put("/users/{id}", updateUser)
r.Delete("/users/{id}", deleteUser)
// MuxMaster — lowercase → uppercase method names
mux := muxmaster.New()
mux.GET("/users", listUsers)
mux.POST("/users", createUser)
mux.GET("/users/:id", getUser)      // chi uses {id}, MuxMaster uses :id
mux.PUT("/users/:id", updateUser)
mux.DELETE("/users/:id", deleteUser)

chi uses {param} syntax; MuxMaster uses :param syntax. Regex constraints use the same {param:regexp} syntax in both.

Path parameters

// chi
id := chi.URLParam(r, "id")
// MuxMaster
id := muxmaster.PathParam(r, "id")

Route groups

// chi
r.Route("/api/v1", func(r chi.Router) {
    r.Use(requireAPIKey)
    r.Get("/users", listUsers)
    r.Post("/users", createUser)
})
// MuxMaster — nearly identical
mux.Route("/api/v1", func(g *muxmaster.Group) {
    g.Use(requireAPIKey)
    g.GET("/users", listUsers)
    g.POST("/users", createUser)
})

Inline scoped middleware

// chi
r.With(requireAdmin).Delete("/users/{id}", deleteUser)
// MuxMaster — identical
mux.With(requireAdmin).DELETE("/users/:id", deleteUser)

Mounting sub-routers

// chi
r.Mount("/admin", adminRouter())
// MuxMaster — identical
mux.Mount("/admin", adminRouter())

chi Middleware

chi's middleware package uses the same func(http.Handler) http.Handler signature. All chi middleware is compatible with MuxMaster:

import chimiddleware "github.com/go-chi/chi/v5/middleware"

mux.Use(chimiddleware.Logger)
mux.Use(chimiddleware.Recoverer)

You can migrate gradually: keep using chi middleware while replacing the router.


From httprouter

httprouter has a different handler signature: func(http.ResponseWriter, *http.Request, httprouter.Params). Migrating to MuxMaster requires updating handler signatures to use the standard http.HandlerFunc.

Handler signature

// httprouter
func getUser(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    id := ps.ByName("id")
    // ...
}

router := httprouter.New()
router.GET("/users/:id", getUser)
// MuxMaster — standard net/http signature
func getUser(w http.ResponseWriter, r *http.Request) {
    id := muxmaster.PathParam(r, "id")
    // ...
}

mux := muxmaster.New()
mux.GET("/users/:id", getUser)

For a large codebase, you can write a thin adapter to avoid rewriting all handlers at once:

// Adapter: wraps a httprouter-style handler as a MuxMaster handler
func adapt(h func(http.ResponseWriter, *http.Request, httprouter.Params)) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        ps := muxmaster.ParamsFromContext(r.Context())
        // Convert muxmaster.Params to httprouter.Params
        hrps := make(httprouter.Params, len(ps))
        for i, p := range ps {
            hrps[i] = httprouter.Param{Key: p.Key, Value: p.Value}
        }
        h(w, r, hrps)
    }
}

mux.GET("/users/:id", adapt(getUser))

Route registration

// httprouter
router := httprouter.New()
router.GET("/users", listUsers)
router.POST("/users", createUser)
router.GET("/users/:id", getUser)
// MuxMaster — identical route patterns, different handler type
mux := muxmaster.New()
mux.GET("/users", listUsers)
mux.POST("/users", createUser)
mux.GET("/users/:id", getUser)

Custom error handlers

// httprouter
router.NotFound         = myNotFoundHandler
router.MethodNotAllowed = myMethodNotAllowedHandler
router.PanicHandler     = myPanicHandler
// MuxMaster — identical
mux.NotFound         = myNotFoundHandler
mux.MethodNotAllowed = myMethodNotAllowedHandler
mux.PanicHandler     = myPanicHandler

From net/http ServeMux

net/http.ServeMux does not support path parameters or middleware. Migration to MuxMaster adds these capabilities without changing handler code.

// net/http
mux := http.NewServeMux()
mux.HandleFunc("/users", listUsers)
mux.HandleFunc("/users/", userDetail) // catches /users/anything
// MuxMaster — explicit path parameters
mux := muxmaster.New()
mux.GET("/users", listUsers)
mux.GET("/users/:id", userDetail)

Handler code that uses r.URL.Path to extract the "parameter" can be simplified:

// net/http — manual extraction
func userDetail(w http.ResponseWriter, r *http.Request) {
    id := strings.TrimPrefix(r.URL.Path, "/users/")
    // ...
}

// MuxMaster — automatic extraction
func userDetail(w http.ResponseWriter, r *http.Request) {
    id := muxmaster.PathParam(r, "id")
    // ...
}

Common Adjustments

Parameter syntax

Router Named param Catch-all Regex param
gorilla/mux {id} {id:[0-9]+}
chi {id} * {id:[0-9]+}
httprouter :id *id
MuxMaster :id *id {id:[0-9]+}

Middleware compatibility

Any middleware with the signature func(http.Handler) http.Handler is compatible with MuxMaster. This covers:

  • All chi middleware (github.com/go-chi/chi/v5/middleware)
  • All gorilla handlers with that signature
  • Most popular community middleware packages

Trailing slash behaviour

MuxMaster redirects trailing slashes by default (RedirectTrailingSlash = true). If your application registers both /users and /users/ as separate routes, disable this:

mux.RedirectTrailingSlash = false

See Also

  • Routing — complete pattern syntax reference
  • Middleware — built-in and custom middleware
  • Groups — organizing routes with groups and sub-routers
  • Configuration — all router options

Upstream source

The authoritative list of MuxMaster releases, breaking changes, and deprecations referenced above lives in CHANGELOG.md in the upstream repository.

Common questions

How do I migrate a chi router to MuxMaster?

Replace chi.NewRouter() with mux.New(), the route helpers (Get, Post, etc.) keep their names, and chi.URLParam(r, "id") becomes mux.Param(r, "id"). Most chi middlewares run unchanged because both routers expose the same func(http.Handler) http.Handler shape.

How do I migrate a gorilla/mux router?

Replace mux.NewRouter() with muxmaster.New() (alias the import to keep call sites short) and rename r.HandleFunc("/path", h).Methods("GET") to m.GET("/path", h). Path parameters use the same colon-prefix syntax in both libraries; named regex constraints have no equivalent and must be moved into handler-level validation.

Which gorilla/mux features have no MuxMaster equivalent?

Schemes/host matchers, named regex constraints, and the Middleware trie are intentionally omitted to keep the router small and zero-allocation. Schemes and hosts belong in the reverse proxy or a Pre middleware; regex constraints belong in handler-level validation; middleware trie behaviour is achieved via groups and Use.