go-grpc-middleware: chaining interceptors for auth, logging, retries and recovery in Go
Golang gRPC Middlewares: interceptor chaining, auth, logging, retries and more.
At a glance
- What is it?
- A v2 module of ready-made gRPC interceptors for Go, plus a selector for scoping them and a Prometheus provider that moved out of go-grpc-prometheus. The design is deliberately thin, and that is both the reason to use it and the reason to check your edge cases first.
- Who is it for?
- Adopt it if you run grpc-go services in Go and want auth, logging, recovery and Prometheus metrics wired in one place instead of hand-rolling each interceptor. Skip it if you need advanced retry policies, since the README points at grpc-go's native retries for those, or if you want a framework that owns your edge cases, because the README says this repo cannot support all of them.
- Can I use it commercially?
- Yes. Apache-2.0 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 33 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 September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What go-grpc-middleware is for, and who ends up importing it
grpc-go already has interceptors: functions that run on the server before a request reaches your handler, or on the client around a call. What it does not ship is a catalogue of them. go-grpc-middleware fills that gap with ready-to-use interceptors for auth, logging, metrics, retries, timeouts, validation and panic recovery, and the README frames the target audience plainly: teams building multiple microservices who want shared, consistent behaviour across every method without copying the same boilerplate into each service.
The second thing it provides is chaining. grpc.ChainUnaryInterceptor and grpc.ChainStreamInterceptor let you stack interceptors, and the README's argument is that this makes observability semi-automatic. Logs, traces and metrics all pass through the same pipeline, so a trace ID can be attached in one interceptor and read by the next, which is what makes correlation techniques like exemplars workable.
The scope is narrower than the name suggests. The README lists external interceptors alongside its own, including google.golang.org/grpc/authz for policy-based auth and go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc for tracing. The project is a starting point and a set of building blocks, not an attempt to own every concern.
How interceptor chaining works in a go-grpc-middleware server
The mechanism is the grpc-go interceptor API plus a fixed ordering discipline. You pass an ordered list to grpc.NewServer, and each interceptor wraps the next, so the order you write is the order requests traverse.
The README's server example builds a chain of four unary interceptors: Prometheus metrics, logging, auth wrapped in a selector, and recovery. The same four appear again as stream interceptors, because unary and streaming calls are configured separately and neither chain covers the other.
Two ordering rules are stated rather than implied. Recovery must be the last interceptor so a panic does not skip the ones behind it. And interceptors that inject fields into the context must be chained before the logging adapter function, otherwise the adapter has nothing to read. Both are easy to get wrong silently, since a misordered chain still compiles and still serves traffic.
The selector package is what keeps auth from applying everywhere. In the example, selector.UnaryServerInterceptor wraps auth.UnaryServerInterceptor and selector.MatchFunc(allButHealthZ) decides which methods it applies to, so health checks stay unauthenticated. That is a small piece of the module but it is the difference between usable and not on a server that exposes health endpoints.
Installing go-grpc-middleware v2 and wiring a first chain
The README states that all interceptor paths work with go get. The module path is versioned, so the import carries /v2.
go get github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recoveryA minimal server chain combines recovery with logging. The logging interceptor needs an adapter, and the README points to interceptors/logging/examples for go-kit, log, logr, logrus, slog, zap and zerolog. Recovery takes a handler so you control what the client sees.
import (
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
)
grpcSrv := grpc.NewServer(
grpc.ChainUnaryInterceptor(
logging.UnaryServerInterceptor(interceptorLogger(rpcLogger)),
recovery.UnaryServerInterceptor(recovery.WithRecoveryHandler(grpcPanicRecoveryHandler)),
),
)After starting the server, send a request that panics inside your handler. The recovery interceptor turns it into a gRPC error instead of taking the process down, and the logging interceptor records the call. The README notes that recovery should be last in the chain, which is why it sits below logging here.
The client-side interceptors follow the same shape. Retry and timeout are both documented as client middleware, so they go into grpc.WithChainUnaryInterceptor on the dial side rather than into the server.
The Prometheus provider and where exemplars fit
The metrics interceptor lives at providers/prometheus rather than under interceptors, and it is versioned separately: the release list shows providers/prometheus/v1.1.0 dated 2025-06-16, distinct from the v2.3.x line. The README says it moved from the now-deprecated go-grpc-prometheus, so anyone still importing that module has a migration to plan.
It provides both client-side and server-side monitoring middleware and supports exemplars. In the README's server example, the interceptor is configured with grpcprom.WithExemplarFromContext and grpcprom.WithLabelsFromContext, which pull values out of the request context. That is the concrete payoff of chaining: an earlier interceptor or the stats handler puts a trace ID in the context, the metrics interceptor attaches it to the observation, and you can jump from a latency spike in Prometheus to the trace that produced it.
The example server also passes grpc.StatsHandler(otelgrpc.NewServerHandler()) to grpc.NewServer. That is the OpenTelemetry handler from the contrib module, not part of this repository, and it sits alongside the middleware chain rather than inside it. Keeping the two straight matters when you debug why a span is missing.
Where go-grpc-middleware stops being the right tool
The README is unusually direct about the limits. It says some middlewares are simple enough that you should treat the repo as a template and copy the simpler interceptors if you need more flexibility, and it states that the repo cannot support all the edge cases you might have. That is an honest boundary, and it means the library is a default, not a guarantee.
The retry interceptor carries a similar caveat. The README describes it as a generic response-code retry mechanism and then notes that grpc-go has native retries with advanced policies. If your retry logic depends on backoff configuration or per-method policy, the native path is the one the project itself points at.
There is also a maintenance shape to account for. The repository is not archived and the last push was on 2026-08-28, with v2.3.4 released the same day, after v2.3.3 on 2025-11-04. Those two releases are roughly ten months apart. That is a stable cadence rather than a fast-moving one, so if you need a fix in an interceptor, expect to carry a fork or a local copy. The README's suggestion to copy simple interceptors is effectively the project's answer to that.
Finally, the module requires Go 1.24.0 per go.mod. Teams pinned to an older toolchain cannot adopt the current v2 line without upgrading.
Choosing between this and grpc-go's built-in interceptors
The real alternative is not another middleware library. It is writing interceptors yourself against the grpc-go API, which is what this project is built on.
The difference in approach is packaging versus control. A hand-written interceptor is a function with a signature you already know from grpc.UnaryServerInterceptor, and it does exactly what you wrote, nothing more. You own the logging format, the retry conditions, the panic handler. The cost is that every service in your fleet reimplements the same function, and consistency across services becomes a review problem rather than a dependency.
Adopting go-grpc-middleware inverts that. You get a shared implementation and a documented chain order, and the README's correlation argument holds: context injection plus a logging adapter plus exemplars is a lot of plumbing to reproduce by hand. You give up the freedom to shape each interceptor to an unusual edge case, which is precisely the freedom the README tells you to reclaim by copying.
There is a middle position worth naming. The README lists external interceptors for the areas where dedicated projects do better, notably authz for policy-based authorization and otelgrpc for tracing. Mixing those with this module's logging, recovery and metrics interceptors in one chain is a normal configuration, not a workaround.
Licence, upgrade cost and what the repository layout implies
The project is Apache-2.0, stated in the README badge and present as a LICENSE file at the repository root alongside COPYRIGHT. Apache-2.0 is permissive and includes an explicit patent grant. That is the licence text; whether it fits your distribution model is a question for your own counsel, not something this article can settle.
Upgrade cost is shaped by the module layout. The root module is github.com/grpc-ecosystem/go-grpc-middleware/v2, and providers/prometheus is a separate module with its own go.mod and its own version tags, which the Makefile confirms by discovering provider modules and running go mod tidy across each of them. You upgrade the two independently, and a Prometheus provider bump does not require a root module bump.
The v1 to v2 move is the expensive one for existing users. The README links v1 paths such as tracing/opentracing on pkg.go.dev with a deprecated marker, and the Prometheus provider's move away from go-grpc-prometheus is a second migration on the same codebase. Neither is described in the README as having an automated path, so treat both as manual work sized against how many interceptors you actually use.
One more layout detail: examples/ is its own module with its own go.mod, so the runnable server and client are not pulled into your dependency graph when you import the library.
Editorial conclusion
Adopt it if you run grpc-go services in Go and want auth, logging, recovery and Prometheus metrics wired in one place instead of hand-rolling each interceptor. Skip it if you need advanced retry policies, since the README points at grpc-go's native retries for those, or if you want a framework that owns your edge cases, because the README says this repo cannot support all of them. Verify two things before you commit: that the interceptor order in your grpc.NewServer call puts recovery last and any context-injecting interceptor before the logging adapter, and that the module path you import is the v2 one, since several v1 paths are documented as deprecated.
Frequently asked questions
How do I install go-grpc-middleware?
Fetch the specific interceptor package you need with go get, for example go get github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery. The README states that all interceptor paths work with go get, and the module path carries the /v2 suffix.
Which order should go-grpc-middleware interceptors be chained in?
The README says recovery should be used as the last interceptor so a panic does not skip the others, and that interceptors which inject context fields must be chained before the logging adapter function. The server example orders metrics, logging, auth and then recovery.
Does go-grpc-middleware handle retries?
It ships a client-side retry interceptor described as a generic gRPC response code retry mechanism. The README also notes that grpc-go has native retries with advanced policies, so the built-in path may fit better when you need complex policy.
What is go-grpc-middleware used for?
It provides ready-to-use gRPC Go interceptors for auth, logging, metrics, retries, timeouts, validation and panic recovery, plus helpers for chaining them. The README describes interceptors as a way to implement common patterns as generic building blocks shared across microservices.
Is go-grpc-middleware still maintained?
The repository is not archived. The last push was on 2026-08-28, which is also the date of the v2.3.4 release; the previous release, v2.3.3, was on 2025-11-04.
Official sources
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.
[](https://hysenlabs.com/projects/grpc-ecosystem-go-grpc-middleware)