Last Updated: 3/11/2026
Middleware
Middleware in Hono processes requests before they reach route handlers. It’s perfect for authentication, logging, CORS, and other cross-cutting concerns.
Using Middleware
Apply middleware with app.use():
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { cors } from 'hono/cors'
const app = new Hono()
// Apply to all routes
app.use(logger())
// Apply to specific paths
app.use('/api/*', cors())
app.get('/api/data', (c) => c.json({ data: 'example' }))Built-in Middleware
Hono includes many built-in middleware:
Logger
Log requests to the console:
import { logger } from 'hono/logger'
app.use(logger())CORS
Handle Cross-Origin Resource Sharing:
import { cors } from 'hono/cors'
app.use('/api/*', cors())
// With options
app.use(
'/api/*',
cors({
origin: 'https://example.com',
allowMethods: ['GET', 'POST'],
credentials: true,
})
)Basic Auth
Add HTTP Basic Authentication:
import { basicAuth } from 'hono/basic-auth'
app.use(
'/admin/*',
basicAuth({
username: 'admin',
password: 'secret',
})
)
app.get('/admin', (c) => c.text('You are authorized!'))Bearer Auth
Authenticate with Bearer tokens:
import { bearerAuth } from 'hono/bearer-auth'
app.use(
'/api/*',
bearerAuth({
token: 'your-secret-token',
})
)JWT Auth
Validate JSON Web Tokens:
import { jwt } from 'hono/jwt'
app.use(
'/protected/*',
jwt({
secret: 'your-secret-key',
})
)
app.get('/protected/data', (c) => {
const payload = c.get('jwtPayload')
return c.json({ user: payload })
})ETag
Add ETag headers for caching:
import { etag } from 'hono/etag'
app.use(etag())Compress
Compress responses:
import { compress } from 'hono/compress'
app.use(compress())Pretty JSON
Format JSON responses:
import { prettyJSON } from 'hono/pretty-json'
app.use(prettyJSON())Secure Headers
Add security headers:
import { secureHeaders } from 'hono/secure-headers'
app.use(secureHeaders())Custom Middleware
Create your own middleware with createMiddleware:
import { createMiddleware } from 'hono/factory'
const customLogger = createMiddleware(async (c, next) => {
console.log(`[${c.req.method}] ${c.req.url}`)
await next()
console.log(`Response status: ${c.res.status}`)
})
app.use(customLogger)Middleware with Variables
Pass data to handlers:
import { createMiddleware } from 'hono/factory'
type Env = {
Variables: {
requestId: string
}
}
const requestId = createMiddleware<Env>(async (c, next) => {
const id = crypto.randomUUID()
c.set('requestId', id)
await next()
})
app.use(requestId)
app.get('/', (c) => {
const id = c.get('requestId')
return c.json({ requestId: id })
})Middleware Order
Middleware executes in registration order:
app.use(logger()) // 1. Logs request
app.use(cors()) // 2. Handles CORS
app.use(basicAuth({ ... })) // 3. Authenticates
app.get('/api/data', (c) => {
// 4. Handler executes
return c.json({ data: 'example' })
})Path-Specific Middleware
Apply middleware to specific paths:
// Apply to all /api routes
app.use('/api/*', logger())
// Apply to specific route
app.get('/admin', basicAuth({ ... }), (c) => {
return c.text('Admin panel')
})Third-Party Middleware
Hono has a rich ecosystem of third-party middleware:
- @hono/zod-validator - Validation with Zod
- @hono/sentry - Error tracking
- @hono/graphql-server - GraphQL server
- @hono/firebase-auth - Firebase authentication
Install and use:
npm install @hono/zod-validator zodimport { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
app.post(
'/posts',
zValidator(
'json',
z.object({
title: z.string(),
body: z.string(),
})
),
(c) => {
const { title, body } = c.req.valid('json')
return c.json({ title, body })
}
)Error Handling Middleware
Handle errors globally:
app.use(async (c, next) => {
try {
await next()
} catch (err) {
console.error('Error:', err)
return c.json({ error: 'Internal Server Error' }, 500)
}
})Or use app.onError():
app.onError((err, c) => {
console.error(`${err}`)
return c.json({ error: err.message }, 500)
})Next Steps
Explore specific middleware in the Reference section, or learn about Validation.