Skip to main content

What is Middleware?

Middleware is a function that runs before your route handler. It can modify the request, response, or perform side effects like logging, authentication, or error handling. Middleware functions have access to the context object and a next() function to pass control to the next middleware or route handler.

Middleware Execution Flow

Middleware executes in the order it’s registered:
const app = new Hono()

app.use('*', async (c, next) => {
  console.log('1. First middleware - before')
  await next()
  console.log('1. First middleware - after')
})

app.use('*', async (c, next) => {
  console.log('2. Second middleware - before')
  await next()
  console.log('2. Second middleware - after')
})

app.get('/hello', (c) => {
  console.log('3. Route handler')
  return c.text('Hello!')
})

// Request to /hello outputs:
// 1. First middleware - before
// 2. Second middleware - before
// 3. Route handler
// 2. Second middleware - after
// 1. First middleware - after
This “onion model” allows middleware to execute code both before and after the route handler.

Using Middleware with app.use()

The app.use() method registers middleware. It can be used in several ways:

Global Middleware

Apply middleware to all routes:
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('Home'))
app.get('/about', (c) => c.text('About'))

Route-Specific Middleware

Apply middleware to specific routes or paths:
import { Hono } from 'hono'
import { jwt } from 'hono/jwt'
import { cors } from 'hono/cors'

const app = new Hono()

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

// Applies to /auth/* routes
app.use('/auth/*', jwt({ secret: 'secret-key', alg: 'HS256' }))

app.get('/api/posts', (c) => c.json({ posts: [] }))
app.get('/auth/profile', (c) => c.json({ user: 'John' }))
app.get('/public', (c) => c.text('Public page')) // No middleware

Multiple Middleware

Chain multiple middleware together:
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
import { jwt } from 'hono/jwt'

const app = new Hono()

// Multiple middleware in one call
app.use('/api/*', logger(), cors(), jwt({ secret: 'secret', alg: 'HS256' }))

// Or chain them
app.use('/api/*', logger())
app.use('/api/*', cors())
app.use('/api/*', jwt({ secret: 'secret', alg: 'HS256' }))

Middleware Ordering

Middleware order matters! They execute in the order they’re registered:
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { jwt } from 'hono/jwt'

const app = new Hono()

// ✅ Correct: Logger runs first, then auth
app.use('*', logger())
app.use('/api/*', jwt({ secret: 'secret', alg: 'HS256' }))

// ❌ Wrong: Auth runs before logger
app.use('/api/*', jwt({ secret: 'secret', alg: 'HS256' }))
app.use('*', logger()) // This won't log auth errors
Global middleware (using * or no path) should typically be registered first, followed by more specific path-based middleware.

Middleware Pattern Matching

Path patterns determine when middleware executes:
import { Hono } from 'hono'
import { logger } from 'hono/logger'

const app = new Hono()

// All routes
app.use('*', logger())

// Routes starting with /api/
app.use('/api/*', logger())

// Exact route
app.use('/admin', logger())

// Routes with parameters
app.use('/users/:id', logger())

// Multiple segments
app.use('/api/v1/*', logger())

Built-in vs Custom vs Third-Party

Hono provides three types of middleware:

Built-in Middleware

Shipped with Hono and ready to use:
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
import { jwt } from 'hono/jwt'

const app = new Hono()

app.use(logger())
app.use('/api/*', cors())
app.use('/auth/*', jwt({ secret: 'secret', alg: 'HS256' }))

Custom Middleware

Create your own middleware for specific needs:
import { Hono } from 'hono'
import type { MiddlewareHandler } from 'hono'

const app = new Hono()

const customMiddleware: MiddlewareHandler = async (c, next) => {
  // Your logic here
  await next()
}

app.use(customMiddleware)

Third-Party Middleware

Middleware from the community or other compatible libraries:
import { Hono } from 'hono'
import { someThirdPartyMiddleware } from 'third-party-package'

const app = new Hono()

app.use(someThirdPartyMiddleware())

Next Steps

Built-in Middleware

Explore all built-in middleware that ships with Hono

Custom Middleware

Learn how to create your own middleware

Third-Party Middleware

Integrate external middleware packages

Build docs developers (and LLMs) love