# How to Define and Apply Custom Middleware Chains in Kratos: A Complete Guide

> Master Kratos middleware chains. Implement custom MWs, chain them with middleware.Chain, and apply globally or selectively. Enhance your Kratos app now.

- Repository: [Kratos/kratos](https://github.com/go-kratos/kratos)
- Tags: how-to-guide
- Published: 2026-03-02

---

**Define custom middleware chains in Kratos by implementing the `Middleware` type as a higher-order function, compose multiple middlewares using `middleware.Chain`, and apply them globally via server options, selectively via the `Use` method with path selectors, or per-client via `WithMiddleware`.**

The Kratos framework from the `go-kratos/kratos` repository treats every cross-cutting concern—such as logging, authentication, tracing, and validation—as a middleware. Understanding how to define and apply custom middleware chains in Kratos allows you to build flexible, reusable processing pipelines for both HTTP and gRPC transports.

## Understanding the Kratos Middleware Interface

At the core of Kratos middleware architecture are two type definitions located in [`middleware/middleware.go`](https://github.com/go-kratos/kratos/blob/main/middleware/middleware.go). The `Handler` represents the endpoint execution, while `Middleware` is a higher-order function that wraps a `Handler` to intercept requests and responses.

```go
// middleware/middleware.go
type Handler   func(ctx context.Context, req any) (any, error)
type Middleware func(Handler) Handler

```

Every custom middleware you create must conform to the `Middleware` signature. It receives a `Handler` and returns a new `Handler` that executes your custom logic before or after calling the next handler in the chain.

## Composing Middleware with Chain

The `middleware.Chain` function composes multiple `Middleware` values into a single executable chain. According to the implementation in [`middleware/middleware.go`](https://github.com/go-kratos/kratos/blob/main/middleware/middleware.go), the chain executes **right-to-left**, meaning the first middleware passed to `Chain` becomes the outermost wrapper and executes first on the way in and last on the way out.

```go
// Example: Building a custom middleware chain
authMw := func(next middleware.Handler) middleware.Handler {
    return func(ctx context.Context, req any) (any, error) {
        // Authentication logic
        if !validateToken(ctx) {
            return nil, errors.Unauthenticated("invalid token")
        }
        return next(ctx, req)
    }
}

logMw := func(next middleware.Handler) middleware.Handler {
    return func(ctx context.Context, req any) (any, error) {
        log.Infof("request: %v", req)
        resp, err := next(ctx, req)
        log.Infof("response: %v, err: %v", resp, err)
        return resp, err
    }
}

// Compose them: auth runs first, then logging, then the handler
myChain := middleware.Chain(authMw, logMw)

```

## Applying Middleware Chains in Kratos

Kratos provides four distinct scopes for applying your custom middleware chains, each controlled through different configuration points in the transport layer.

### Server-Wide Configuration

To apply a middleware chain to every request handled by an HTTP or gRPC server, pass the chain as a server option. In [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go) and [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go), the `Middleware` option accepts a pre-composed chain.

```go
// HTTP server with global middleware
srv := http.NewServer(
    http.Address(":8080"),
    http.Middleware(myChain), // Applies to all HTTP routes
)

// gRPC server with global middleware
grpcSrv := grpc.NewServer(
    grpc.Middleware(myChain), // Applies to all gRPC methods
)

```

### Service-Level and Method-Level Application

For selective application, the `Server.Use` method accepts a path selector and variadic middlewares. As implemented in both [`transport/http/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/server.go) and [`transport/grpc/server.go`](https://github.com/go-kratos/kratos/blob/main/transport/grpc/server.go), Kratos stores these in a `matcher.Matcher` instance and assembles the chain at request time based on the operation name.

```go
grpcSrv := grpc.NewServer()
// Apply only to Greeter service methods
grpcSrv.Use("/helloworld.v1.Greeter/*", authMw, logMw)

```

The selector supports wildcard patterns, allowing you to target specific services or individual methods without affecting others.

### Client-Side Middleware Application

When constructing HTTP or gRPC clients in [`transport/http/client.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/client.go), use the `WithMiddleware` option to attach middleware chains to all outgoing calls from that client instance.

```go
cli, _ := http.NewClient(
    context.Background(),
    http.WithEndpoint("http://127.0.0.1:8080"),
    http.WithMiddleware(authMw, logMw), // Applies to all outgoing calls
)

```

Internally, the client's `invoke` method checks `client.opts.middleware` and builds a temporary chain using `middleware.Chain(client.opts.middleware...)(h)` before executing the request.

### Per-Call Middleware Wrapping

For one-off execution or dynamic composition, manually wrap a handler with your chain at the call site. This pattern bypasses the automatic middleware assembly and gives you direct control over the execution flow.

```go
handler := func(ctx context.Context, req any) (any, error) {
    // Actual business logic
    return processRequest(ctx, req)
}

// Wrap and execute immediately
wrapped := myChain(handler)
resp, err := wrapped(ctx, req)

```

## Practical Implementation Examples

The following examples demonstrate complete, reusable middleware implementations that work across both HTTP and gRPC transports.

**Logging Middleware**

```go
// internal/mw/logging.go
func Logging() middleware.Middleware {
    return func(next middleware.Handler) middleware.Handler {
        return func(ctx context.Context, req any) (any, error) {
            log.Infof("[REQ] %v", req)
            resp, err := next(ctx, req)
            log.Infof("[RESP] %v, err=%v", resp, err)
            return resp, err
        }
    }
}

```

**Authentication Middleware**

```go
// internal/mw/auth.go
func Auth() middleware.Middleware {
    return func(next middleware.Handler) middleware.Handler {
        return func(ctx context context.Context, req any) (any, error) {
            token := extractToken(ctx)
            if !validateToken(token) {
                return nil, errors.Unauthenticated("invalid token")
            }
            return next(ctx, req)
        }
    }
}

```

**Complete Server Setup**

```go
// Global application
srv := http.NewServer(
    http.Address(":8080"),
    http.Middleware(middleware.Chain(mw.Auth(), mw.Logging())),
)

// Service-specific application
grpcSrv := grpc.NewServer()
grpcSrv.Use("/helloworld.v1.Greeter/*", mw.Auth(), mw.Logging())

```

## Summary

- **Define** custom middleware by implementing the `func(Handler) Handler` signature defined in [`middleware/middleware.go`](https://github.com/go-kratos/kratos/blob/main/middleware/middleware.go).
- **Compose** multiple middlewares using `middleware.Chain`, which executes them right-to-left (first middleware wraps outermost).
- **Apply globally** using `http.Middleware()` or `grpc.Middleware()` server options to affect all traffic.
- **Apply selectively** using `srv.Use(selector, m...)` with path patterns to target specific services or methods, utilizing the [`internal/matcher/matcher.go`](https://github.com/go-kratos/kratos/blob/main/internal/matcher/matcher.go) implementation.
- **Apply on clients** using `http.WithMiddleware()` when constructing clients in [`transport/http/client.go`](https://github.com/go-kratos/kratos/blob/main/transport/http/client.go).
- **Reuse** the same middleware implementations across both HTTP and gRPC transports since both use the identical `Middleware` type.

## Frequently Asked Questions

### What is the execution order of middleware.Chain in Kratos?

`middleware.Chain` executes middlewares **right-to-left**. When you call `middleware.Chain(authMw, logMw, recoveryMw)`, the execution flow is: `authMw` executes first, calls `logMw`, which calls `recoveryMw`, which finally calls the handler. On the return path, the order reverses.

### How do I apply different middleware to specific gRPC methods?

Use the `Use` method on your gRPC server instance with a path selector. For example, `grpcSrv.Use("/helloworld.v1.Greeter/SayHello", authMw)` applies `authMw` only to the `SayHello` method. Wildcards like `/helloworld.v1.Greeter/*` apply to all methods in the Greeter service.

### Can I reuse the same middleware for both HTTP and gRPC in Kratos?

Yes. Both the HTTP transport (`transport/http`) and gRPC transport (`transport/grpc`) import and use the same `Middleware` type defined in [`middleware/middleware.go`](https://github.com/go-kratos/kratos/blob/main/middleware/middleware.go). A single middleware implementation works across both protocols without modification.

### How do I pass metadata between middleware in Kratos?

Use the `context.Context` to carry values between middleware layers. Extract information in an upstream middleware using `ctx = context.WithValue(ctx, key, value)`, then retrieve it in downstream middleware or the final handler using `ctx.Value(key)`. Ensure you use struct keys rather than string keys to avoid collisions.