Skip to content

Zinc

v0.7.3MITGo 1.25+

Galvanize net/http.

The high-performance, minimalist web layer for Go. Routing, binding, errors, and 27 middleware packages, applied as a thin coat over the standard library you already trust.

main.go
app := zinc.New() app.Get("/users/{id}", func(c *zinc.Context) error {	user, ok := users[c.Param("id")]	if !ok {		return zinc.NotFound("user not found")	}	return c.JSON(user)}) app.Listen(":8080")

$ curl -i localhost:8080/users/42

HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8

{"id":"42","name":"Ada Lovelace"}

What you get

One request, start to finish.

From the first middleware to the response, each step is a few lines of Go.

app.Use(
    requestid.New(),
    logger.New(),
    recover.New(),
    secure.New(),
)

api := app.Group("/api", timeout.New(timeout.Config{Timeout: 5 * time.Second}))

L2Every response carries an ID that your logs share.Guide →

GET /api/users/42

200 OK

X-Request-Id: 9f2c4e1a7b3d5c8e0a6f1b2c3d4e5f60

X-Content-Type-Options: nosniff

X-Frame-Options: SAMEORIGIN

OpenAPI · built in

Your types are the spec.

Every app serves an OpenAPI 3.1 spec at /openapi.json and a reference page at /docs, built from the handlers you already wrote. A rule shows up in the spec only when Zinc checks it on requests.

users.goGET /openapi.json · GET /docs
type CreateUser struct {
    OrgID  string `path:"org"`
    DryRun bool   `query:"dry_run"`
    Email  string `json:"email" validate:"required,email"`
}

api.Post("/orgs/{org}/users", zinc.Typed(createUser)).
    Status(http.StatusCreated)

In the specorg · in: path · string · required

POST /api/orgs/acme/users {"email":"ada@example.com"}

201 {"id":1,"org_id":"acme","email":"ada@example.com"}

Pick one to see it in the spec and on the wire.

How it fits

A thin coat, not a new engine.

Galvanizing protects steel without replacing it. Zinc does the same for net/http: your app is still an http.Handler, and standard handlers, middleware, and servers plug straight in.

Pick one to see where it plugs into the stack.

Zinc and net/http →
Section A–Arequest ↑ · response ↓
Your applicationhandlers · services · packages
listUserscreateUserpromhttp.Handler()

zinc.HandlerFunchttp.Handler

Zincrouting · binding · errors · middleware
Standard middlewareotelhttp · func(http.Handler) http.Handler
net/httpthe standard library, untouched
http.Server{Handler: app}*http.Requesthttp.ResponseWriter
http.Handler inhttp.Handler out

Measured, in the repo

61/ 93

Scenarios where Zinc recorded the lowest latency against Gin and Echo. On average it was 6.1% from the fastest. Gin led 21 and Echo 2. Against the bare routers BunRouter and Chi, Zinc led 32 of 66. All were measured together in one run for 0.7.3.

Zinc fastestA tie within 3%A rival fastest

5 October 2026Apple M1 Pro · go1.27.1 · commit 2a51380

Full benchmark report →

HelloWorldns/op · lower is faster

  1. Zinc84.12fastest
  2. Gin137.91.64×
  3. Echo151.61.80×

Middleware

A periodic table of production parts.

Numbered in chain order: each part wraps everything after it. Select parts to galvanize them into a stack, and the table writes the app.Use call in the right order.

Start from
Observe1–6Sees every request, so it wraps the rest
  1. ↗
  2. ↗
  3. ↗
  4. ↗
  5. ↗
  6. ↗
Contain7–10Bounds panics, time, size, and load
  1. ↗
  2. ↗
  3. ↗
  4. ↗
Shape11–14Normalises the URL before routing
  1. ↗
  2. ↗
  3. ↗
  4. ↗
Guard15–23Decides who gets in
  1. ↗
  2. ↗
  3. ↗
  4. ↗
  5. ↗
  6. ↗
  7. ↗
  8. ↗
  9. ↗
Carry24–29Encodes and serves the response
  1. ↗
  2. ↗
  3. ↗
  4. ↗
  5. ↗
  6. ↗

Your compound

RiLgRcSh

4 parts, outermost first

main.go
app.Use(
	requestid.New(),
	logger.New(),
	recover.New(),
	secure.New(),
)

Coat your first service.

Start a new API in a few minutes, or add Zinc to a service you already run.