Discussion: Adopting go-chi/chi as the HTTP router for LabKit v2

As part of ongoing work in LabKit v2, we're evaluating whether to adopt go-chi/chi as the standard HTTP router for all Go services within GitLab.

This follows the same process used for slog adoption: an open discussion where senior technical leadership and Go service maintainers can raise concerns, suggest alternatives, or approve the direction. We want explicit alignment before v2/httpserver ships, since the router choice affects every Go service that adopts LabKit v2.

This issue is intended to be a place where team members can raise concerns or additional requirements that need to be catered to going forward.

Justification

The proposed v2/httpserver package introduces an abstract Router interface designed so the underlying HTTP framework can be swapped without breaking consumers (team-tasks#4283). Before this package ships, we need alignment on which router backs the interface by default, since that choice affects the interface design, the middleware story, and the dependency footprint of every Go service that adopts LabKit v2.

Services today that need route grouping, scoped middleware, or sub-router mounting bring their own routers (Gorilla, Chi, or custom), creating the same fragmentation we addressed with slog. Standardising on a single router through LabKit v2 eliminates this.

Objectives

  • Standardisation: Define one consistent way of structuring HTTP routing across services, reducing the cognitive load when moving between codebases.
  • Faster iteration by engineering teams: Provide route grouping, scoped middleware, and sub-router mounting out of the box so teams focus on business logic instead of HTTP plumbing.
  • Faster iteration for infrastructure teams: Centralise routing so cross-cutting concerns (rate limiting, circuit breakers, auth middleware) can be rolled out consistently.

Why Chi?

An investigation with benchmarks was conducted in team-tasks#4294. Key findings:

  • Minimal dependency footprint. Chi depends only on the standard library. No transitive dependencies beyond net/http.
  • Stdlib-compatible API. Chi uses standard http.Handler and func(http.Handler) http.Handler middleware signatures. Existing stdlib handlers and middleware work without adapters.
  • Active maintenance. Chi is widely adopted in the Go ecosystem with consistent releases and responsive maintainership.
  • Performance. Comparable to stdlib ServeMux for static routes, faster for parameterized routes. Significantly faster than Gorilla. Full benchmark data is in the investigation issue.

Compared to alternatives:

Router Stdlib-compatible Route groups Scoped middleware Dependencies Status
net/http.ServeMux Yes No No None Active
go-chi/chi Yes Yes Yes None (stdlib only) Active
gorilla/mux Yes No Limited 0 Archived, then revived

The full evaluation (including httprouter, Fiber, Echo, Gin) is in team-tasks#4294.

Prior Art Within GitLab

Chi is not new to GitLab. It has already been evaluated or adopted in several projects:

Project Status Notes
Container Registry Chi migration attempted (2022-2023, gitlab-org#9467) Hayley Swimelar authored MRs, Stan Hu reviewed. Work stalled but validated the approach.
Zoekt Indexer Chi v5.2.5 in production Already shipping with Chi as the HTTP router.
Artifact Registry Evaluating LabKit v2 First new service to adopt v2/httpserver. Router choice directly affects their architecture.

Affected Go Services

The router standardisation would affect these services over time:

Service Current Router Migration Complexity
Container Registry gorilla/mux Medium (prior Chi migration work exists)
GitLab Pages gorilla/mux + handlers + securecookie + sessions High (deep Gorilla dependency)
Workhorse stdlib Low (stdlib routing, Chi is stdlib-compatible)
Gitaly gRPC (minimal HTTP) Low
gitlab-shell gRPC/SSH (no HTTP) Minimal
Runner stdlib Minimal
KAS (gitlab-agent) No HTTP routing Low
Artifact Registry (new) Will use LabKit v2 N/A (greenfield)

Functional Requirements

Based on the design requirements in team-tasks#4283 and current service patterns:

Functionality Notes
Route grouping Scope middleware to route subtrees (e.g. auth on /api/* only)
Method-specific registration r.Get("/path", handler) instead of pattern strings
Per-route middleware r.With(authMW).Get("/admin", handler)
Sub-router mounting r.Mount("/api/v2", apiRouter) for modular route trees
Path parameters Abstracted behind the LabKit Router interface, not framework-specific
Custom 404/405 handlers Override default not-found and method-not-allowed responses
Stdlib fallback Services that don't need Chi's features can continue using ServeMux through the same interface
No framework types in public API Per #4283 (closed) design requirements, all public types are stdlib or LabKit-defined

Migration Strategy

If approved, Chi would be the default router in v2/httpserver:

  1. Resolve this discussion to get alignment on Chi as the default router.
  2. Ship v2/httpserver with Chi backing the Router interface, while keeping the interface implementable by alternative routers.
  3. Validate in a low-risk service (similar to the gitlab-shell approach for slog) before broader rollout.

Approval

This list represents a sample of senior technical leaders from across our engineering org.

Please note: This list is not comprehensive, if you believe that you should be on this list, please feel free to add yourself!

Edited by Arran Walker