Skip to main content
Middleware in Lightning is any function with the HandlerFunc signature:
The Middleware type is an alias for HandlerFunc, so the two are interchangeable. Middleware and route handlers share the same type — a middleware is simply a handler that calls ctx.Next() to pass control to the next function in the chain.

How the chain works

When a request arrives, Lightning executes the handlers in order:
  1. Global middleware (registered with app.Use)
  2. Group middleware (if the route belongs to a group)
  3. Route-level middleware (extra handlers passed to Get, Post, etc.)
  4. The final route handler
Each function in the chain calls ctx.Next() to advance to the next one. You can run logic before ctx.Next() (pre-processing) and logic after it (post-processing).

Global middleware

Register middleware that runs for every request with app.Use. You can pass multiple middlewares in a single call or chain multiple Use calls.
For a request to /, the execution order is:

Route-level middleware

Pass extra handler functions before the final handler to Get, Post, or any other method registration. These run only for that specific route.

Writing a custom middleware

Here is a complete auth middleware that validates a bearer token before allowing the request to proceed.
Attach it globally or per-route:
If you want to abort the request (e.g. due to a failed auth check), return from the middleware without calling ctx.Next(). Lightning will not advance the chain.

Built-in middleware

Lightning ships two middleware functions you can use immediately.

Logger

Logger() logs each request after it completes, reporting the remote address, method, status code, path, elapsed time, and user agent.
Sample log output:
Logger calls ctx.Next() internally and logs on the way back, so it measures total handler time correctly.

Recovery

Recovery() catches any panic that occurs downstream, writes a stack trace to stderr, and returns a 500 response. This prevents a single panicking handler from crashing the entire server.
You can supply a custom handler to control the 500 response:

Using both together

lightning.DefaultApp() is a convenience constructor that registers Logger and Recovery for you:

Complete example