> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/honojs/hono/llms.txt
> Use this file to discover all available pages before exploring further.

# Middleware

> Learn about middleware in Hono, including how middleware executes, creating custom middleware, and the Next function.

## Overview

Middleware are functions that execute during the request-response cycle. They have access to the Context object and can modify the request, response, or pass control to the next middleware.

## What is Middleware?

Middleware functions are handlers that:

* Execute before the final route handler
* Can perform operations like authentication, logging, or validation
* Can modify the request or response
* Must call `next()` to pass control to the next handler
* Can short-circuit the chain by returning a response

From `src/types.ts:83-88`:

```typescript theme={null}
type MiddlewareHandler<
  E extends Env = any,
  P extends string = string,
  I extends Input = {},
  R extends HandlerResponse<any> = Response,
> = (c: Context<E, P, I>, next: Next) => Promise<R | void>
```

## Using Middleware

### Global Middleware

Apply middleware to all routes:

```typescript theme={null}
import { Hono } from 'hono'
import { logger } from 'hono/logger'

const app = new Hono()

// Applies to all routes
app.use('*', logger())

app.get('/', (c) => c.text('Hello'))
app.get('/about', (c) => c.text('About'))
```

### Path-Specific Middleware

Apply middleware to specific paths:

```typescript theme={null}
import { cors } from 'hono/cors'

const app = new Hono()

// Only applies to /api/* routes
app.use('/api/*', cors())

app.get('/api/users', (c) => c.json({ users: [] }))
app.get('/public', (c) => c.text('No CORS here'))
```

### Inline Middleware

Use middleware for specific routes:

```typescript theme={null}
const authenticate = async (c, next) => {
  const token = c.req.header('Authorization')
  if (!token) {
    return c.text('Unauthorized', 401)
  }
  await next()
}

app.get('/protected', authenticate, (c) => {
  return c.text('Protected content')
})
```

## The Next Function

The `next` function passes control to the next middleware or handler in the chain.

From `src/types.ts:35`:

```typescript theme={null}
type Next = () => Promise<void>
```

### Calling Next

```typescript theme={null}
const myMiddleware = async (c, next) => {
  console.log('Before handler')
  await next() // Pass control to next handler
  console.log('After handler')
}

app.use('*', myMiddleware)
app.get('/', (c) => {
  console.log('Handler')
  return c.text('Done')
})

// Output:
// Before handler
// Handler
// After handler
```

<Warning>
  Always `await` the `next()` call. Without `await`, the middleware will continue executing before the handler completes, which can lead to unexpected behavior.
</Warning>

### Multiple Calls to Next

Calling `next()` multiple times throws an error:

```typescript theme={null}
const badMiddleware = async (c, next) => {
  await next()
  await next() // Error: next() called multiple times
}
```

From `src/compose.ts:33-35`:

```typescript theme={null}
if (i <= index) {
  throw new Error('next() called multiple times')
}
```

## Middleware Execution Order

Middleware executes in the order it is defined, following the compose pattern from koa-compose.

From `src/compose.ts:4-73`:

<CodeGroup>
  ```typescript Compose Function theme={null}
  export const compose = <E extends Env = Env>(
    middleware: [[Function, unknown], unknown][] | [[Function]][],
    onError?: ErrorHandler<E>,
    onNotFound?: NotFoundHandler<E>
  ): ((context: Context, next?: Next) => Promise<Context>) => {
    return (context, next) => {
      let index = -1

      return dispatch(0)

      async function dispatch(i: number): Promise<Context> {
        if (i <= index) {
          throw new Error('next() called multiple times')
        }
        index = i

        let res
        let isError = false
        let handler

        if (middleware[i]) {
          handler = middleware[i][0][0]
          context.req.routeIndex = i
        } else {
          handler = (i === middleware.length && next) || undefined
        }

        if (handler) {
          try {
            res = await handler(context, () => dispatch(i + 1))
          } catch (err) {
            if (err instanceof Error && onError) {
              context.error = err
              res = await onError(err, context)
              isError = true
            } else {
              throw err
            }
          }
        } else {
          if (context.finalized === false && onNotFound) {
            res = await onNotFound(context)
          }
        }

        if (res && (context.finalized === false || isError)) {
          context.res = res
        }
        return context
      }
    }
  }
  ```
</CodeGroup>

### Example: Execution Flow

```typescript theme={null}
app.use('*', async (c, next) => {
  console.log('Middleware 1 - Before')
  await next()
  console.log('Middleware 1 - After')
})

app.use('*', async (c, next) => {
  console.log('Middleware 2 - Before')
  await next()
  console.log('Middleware 2 - After')
})

app.get('/', (c) => {
  console.log('Handler')
  return c.text('Done')
})

// Output:
// Middleware 1 - Before
// Middleware 2 - Before
// Handler
// Middleware 2 - After
// Middleware 1 - After
```

## Creating Custom Middleware

### Basic Middleware

```typescript theme={null}
const requestLogger = async (c, next) => {
  const start = Date.now()
  await next()
  const end = Date.now()
  console.log(`${c.req.method} ${c.req.path} - ${end - start}ms`)
}

app.use('*', requestLogger)
```

### Middleware with Configuration

```typescript theme={null}
function rateLimiter(options: { max: number; window: number }) {
  const requests = new Map<string, number[]>()

  return async (c, next) => {
    const ip = c.req.header('x-forwarded-for') || 'unknown'
    const now = Date.now()
    const windowStart = now - options.window

    const userRequests = requests.get(ip) || []
    const recentRequests = userRequests.filter(time => time > windowStart)

    if (recentRequests.length >= options.max) {
      return c.text('Too Many Requests', 429)
    }

    recentRequests.push(now)
    requests.set(ip, recentRequests)
    await next()
  }
}

app.use('*', rateLimiter({ max: 100, window: 60000 }))
```

### Type-Safe Middleware

```typescript theme={null}
import { MiddlewareHandler } from 'hono'

type AuthEnv = {
  Variables: {
    user: { id: string; name: string }
  }
}

const auth: MiddlewareHandler<AuthEnv> = async (c, next) => {
  const token = c.req.header('Authorization')
  
  if (!token) {
    return c.text('Unauthorized', 401)
  }

  // Validate token and get user
  const user = { id: '123', name: 'John' }
  
  c.set('user', user)
  await next()
}

app.use('*', auth)

app.get('/profile', (c) => {
  const user = c.get('user') // Type-safe!
  return c.json(user)
})
```

## Built-in Middleware

Hono provides many built-in middleware for common tasks:

```typescript theme={null}
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
import { basicAuth } from 'hono/basic-auth'
import { bearerAuth } from 'hono/bearer-auth'
import { jwt } from 'hono/jwt'
import { compress } from 'hono/compress'

const app = new Hono()

app.use('*', logger())
app.use('*', cors())
app.use('/admin/*', basicAuth({ username: 'admin', password: 'secret' }))
app.use('/api/*', bearerAuth({ token: 'your-token' }))
```

## Middleware Registration

From `src/hono-base.ts:156-168`:

```typescript theme={null}
this.use = (arg1: string | MiddlewareHandler<any>, ...handlers: MiddlewareHandler<any>[]) => {
  if (typeof arg1 === 'string') {
    this.#path = arg1
  } else {
    this.#path = '*'
    handlers.unshift(arg1)
  }
  handlers.forEach((handler) => {
    this.#addRoute(METHOD_NAME_ALL, this.#path, handler)
  })
  return this as any
}
```

The `use` method:

* Accepts a path (optional) and one or more handlers
* Defaults to `'*'` if no path is provided
* Registers middleware for all HTTP methods

## Short-Circuiting

Middleware can return a response to short-circuit the chain:

```typescript theme={null}
const requireAuth = async (c, next) => {
  const token = c.req.header('Authorization')
  
  if (!token) {
    // Short-circuit: don't call next()
    return c.text('Unauthorized', 401)
  }
  
  // Continue to next handler
  await next()
}

app.use('/api/*', requireAuth)
```

## Error Handling in Middleware

Errors thrown in middleware are caught and passed to the error handler:

```typescript theme={null}
const riskyMiddleware = async (c, next) => {
  try {
    await someAsyncOperation()
    await next()
  } catch (err) {
    // Handle or re-throw
    throw new Error('Middleware failed')
  }
}

app.use('*', riskyMiddleware)

app.onError((err, c) => {
  console.error(err)
  return c.text('Internal Server Error', 500)
})
```

From `src/compose.ts:50-60`, errors are caught during dispatch:

```typescript theme={null}
try {
  res = await handler(context, () => dispatch(i + 1))
} catch (err) {
  if (err instanceof Error && onError) {
    context.error = err
    res = await onError(err, context)
    isError = true
  } else {
    throw err
  }
}
```

## Modifying the Response

Middleware can modify the response after the handler executes:

```typescript theme={null}
const addHeaders = async (c, next) => {
  await next()
  c.header('X-Custom-Header', 'value')
  c.header('X-Response-Time', Date.now().toString())
}

app.use('*', addHeaders)
```

## Best Practices

<Tip>
  * Always `await next()` unless intentionally short-circuiting
  * Register global middleware before route definitions
  * Use specific paths for middleware when possible for better performance
  * Keep middleware focused on a single responsibility
  * Use TypeScript to ensure type safety for context variables
</Tip>

<Warning>
  Avoid calling `next()` multiple times in the same middleware. This will throw an error and stop execution.
</Warning>

## Related

* [Handlers](/concepts/handlers) - Learn about request handlers
* [Context](/concepts/context) - Access request and response data
* [Validation](/concepts/validation) - Validate request data with middleware
