Library / SDK
urfave/negroni avatar
urfave/negroni

negroni is eight files with no module dependencies

Idiomatic HTTP Middleware for Golang

7,526 stars571 forksGoMIT

At a glance

What is it?
A Go middleware library whose whole implementation sits in eight source files at the repository root, with a handler interface that takes a next callback, a default set of three middlewares, and a module file that declares no dependencies at all. Two of its three most recent releases, v3.1.0 and v3.1.1, were published seventeen seconds apart in June 2024, and v3.1.2 followed in October 2026.
Who is it for?
negroni fits a Go service that already uses the standard library's HTTP server and wants a middleware chain without adopting a framework or a router. It does not fit a codebase that wants routing included, because the readme is explicit that you bring your own.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 20 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • urfave/negroni7,526 ★ · -1
Star history
Repository2026-09-222026-11-14
urfave/negroni7.5k7.5k

-1 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The whole library is eight files at the root

The repository layout is the fastest way to understand the scope, and it is unusually flat.

There is a package documentation file, a logger, a recovery middleware, a static file middleware, the main file, and three files all concerned with the response writer: one core, one for feature detection, and one for server push.

Every one of those except the package documentation file and the feature-detection file has a matching test file beside it, and there is a separate benchmark file for the main type.

There are no subdirectories at all except a translations folder, which holds localised copies of the readme. No internal packages, no example directory, no separate module tree.

So the readme's claim that it is tiny is checkable in one directory listing, and the library's behaviour is in principle one afternoon of reading.

Three releases, forty seconds apart

The release history shows v3.1.0 and v3.1.1 on the same afternoon in June 2024, followed by v3.1.2 on 25 October 2026.

The two 2024 tags were published seventeen seconds apart.

The most recent push, on 2026-10-25, coincides with the v3.1.2 release.

So the practical picture is a stable, tiny library with a long gap between the 2024 tags and the October 2026 patch release.

That is a normal state for a small utility library, and it is the state to plan around: pin a release, or pin a commit deliberately, and do not assume a new version is coming on any particular schedule.

The module has no dependencies and the readme quotes an old floor

The module file is four lines: a path, a major version suffix, a language version, and nothing else.

There is no require block. A middleware library that sits in front of every request and has no third-party code in its dependency graph is a meaningful property rather than a boast, because it means a transitive update elsewhere in your build cannot change what happens to your traffic.

Fetching it is a single command with the versioned path:

code
go get github.com/urfave/negroni/v3

The language version declared in the manifest is 1.17, while the getting started instructions say a much older minimum in their own note, that a version from the early 1.x series is required.

The two are not in conflict, since the manifest floor is higher, but the readme's figure is stale and the manifest is what your toolchain reads.

The readme also documents a distribution package option on Debian, installed through the package manager, and notes that at the time of writing it was only in the unstable repository.

The interface is one method with a next callback

The entire extension model is a single interface, and the readme quotes it in full.

It has one method, which takes the response writer, the request, and a next handler function.

The contract is described in one sentence: if a middleware has not already written to the response writer, it should call the next handler in the chain. That is what makes the flow bidirectional rather than a one-way pipeline, because a middleware can do work, delegate, and then do work again on the way out. The readme's example is exactly that shape: something before, the call, something after.

There are two ways to attach middleware. One wraps a plain function into the library's type and adds it to the chain; the other maps an ordinary standard library handler onto the chain directly, which is how a router gets plugged in.

A third convenience function takes existing middlewares and returns a new instance with more, which is how you build a shared base chain and then extend it per group.

It is not a framework, and it does not route

There are two questions in the readme that get one-line answers, and both answers are about what the library refuses to be.

It is not a framework. It is a middleware-focused library designed to work directly with the standard library's HTTP server and handlers.

It does not do routing either. You bring your own router, and the reasoning given is that the Go community already has good routers, so the library tries to work with all of them by supporting the standard library's handler interface.

The example makes the composition rule explicit: create the router, build a new chain with some middlewares, add more with the additive function, then attach the router last and serve.

The positioning against a larger predecessor is stated once as well. If you like the idea of a well-known Martini-style framework but think it contains too much magic, this is the alternative.

Run reads an environment variable, and the flexible path is to pass it as a handler

There are two ways to start a server, and the readme recommends the second.

The convenience function takes an address string identical to the standard library's serve call, and there is a three-line program that builds the default chain and runs it.

If no address is passed, a port environment variable is used, and if that is not defined either, a default address is used.

The recommended approach is instead to use the standard library's own server methods and pass the chain as a handler, which the readme calls more flexible. The example shows why: it configures the standard server type directly, with read and write timeouts and a header size cap, and then serves it.

That example is the most useful thing in the readme, because it shows the library doing exactly what it claims: sitting inside a server you configured, adding nothing.

Route-scoped middleware is a second chain

The last documented feature is per-route middleware, and the mechanism is the convenience function again.

You create a second instance of the chain and hand it to a route group, so the middlewares for that group run only for those routes.

The router example uses a path prefix, passes two middlewares and wraps a nested router, all in one call. A second example builds a subrouter with strict slash handling, and the comments in that snippet call out a trailing path element that is necessary for the subrouter to behave.

Those trailing comments are the kind of thing that ends up in a readme because someone lost an afternoon to it, and they are the clearest signal that route composition, not middleware, is where the friction in this library actually lives.

Which is consistent with everything else about it: the middleware is trivial, and the integration with your router is yours.

Editorial conclusion

negroni fits a Go service that already uses the standard library's HTTP server and wants a middleware chain without adopting a framework or a router. It does not fit a codebase that wants routing included, because the readme is explicit that you bring your own. Before adopting, note that the module path changed with the major version, check the minimum Go version against the manifest rather than the readme, and decide whether the classic defaults are what you want in production.

Frequently asked questions

How do I use negroni in Go?

Build a chain with the constructor or with the classic preset, add your own middleware with the additive function, attach your router last with the handler-mapping call, and serve. The readme recommends configuring the standard library's server type with your own timeouts and passing the chain as its handler, rather than using the convenience run function.

What is Negroni the Go library?

It is an idiomatic middleware library for Go, MIT licensed, that wraps the standard library's HTTP handler. The readme describes it as tiny and non-intrusive, and says it works best for people who like the idea of a Martini-style framework but find it too magical.

How do I install the Negroni Go library?

Fetch it with the Go tool using its versioned module path. Note that the path includes the major version suffix, and that older documentation and copied snippets often show the path without it. On Debian it is also packaged for the unstable repository under a development package name.

What does negroni.Classic() include?

Three default middlewares: panic recovery, a request and response logger, and static file serving from a directory named public. The readme describes this as the easy way to get useful behaviour without configuring anything, and you can add your own on top.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. Releases
  5. urfave/negroni on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/urfave-negroni.svg)](https://hysenlabs.com/projects/urfave-negroni)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/urfave-negroni.svg)](https://hysenlabs.com/projects/urfave-negroni)

Was this useful?