hono-middleware

Hono Middleware Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "hono-middleware" with this command: npx skills add bobmatnyc/claude-mpm-skills/bobmatnyc-claude-mpm-skills-hono-middleware

Hono Middleware Patterns

Overview

Hono provides a powerful middleware system with an "onion" execution model. Middleware processes requests before handlers and responses after handlers, enabling cross-cutting concerns like authentication, logging, and CORS.

Key Features:

  • Onion-style execution order

  • Type-safe middleware creation with createMiddleware

  • 25+ built-in middleware

  • Context variable passing between middleware

  • Async/await support throughout

When to Use This Skill

Use Hono middleware when:

  • Adding authentication/authorization

  • Implementing CORS for cross-origin requests

  • Adding request logging or timing

  • Compressing responses

  • Rate limiting API endpoints

  • Validating requests before handlers

Middleware Basics

Inline Middleware

import { Hono } from 'hono'

const app = new Hono()

// Simple logging middleware app.use('*', async (c, next) => { console.log([${c.req.method}] ${c.req.url}) await next() })

// Path-specific middleware app.use('/api/*', async (c, next) => { const start = Date.now() await next() const ms = Date.now() - start c.header('X-Response-Time', ${ms}ms) })

Execution Order (Onion Model)

app.use(async (c, next) => { console.log('1. Before (first in)') await next() console.log('6. After (first out)') })

app.use(async (c, next) => { console.log('2. Before (second in)') await next() console.log('5. After (second out)') })

app.use(async (c, next) => { console.log('3. Before (third in)') await next() console.log('4. After (third out)') })

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

// Output: // 1. Before (first in) // 2. Before (second in) // 3. Before (third in) // Handler // 4. After (third out) // 5. After (second out) // 6. After (first out)

Creating Reusable Middleware

import { createMiddleware } from 'hono/factory'

// Type-safe reusable middleware const logger = createMiddleware(async (c, next) => { console.log([${new Date().toISOString()}] ${c.req.method} ${c.req.path}) await next() })

// Middleware with options const timing = (headerName = 'X-Response-Time') => { return createMiddleware(async (c, next) => { const start = Date.now() await next() c.header(headerName, ${Date.now() - start}ms) }) }

app.use(logger) app.use(timing('X-Duration'))

Context Variables

Passing Data Between Middleware

import { createMiddleware } from 'hono/factory'

// Define variable types type Variables = { user: { id: string; email: string; role: string } requestId: string }

const app = new Hono<{ Variables: Variables }>()

// Auth middleware sets user const auth = createMiddleware<{ Variables: Variables }>(async (c, next) => { const token = c.req.header('Authorization')?.replace('Bearer ', '')

if (!token) { return c.json({ error: 'Unauthorized' }, 401) }

const user = await verifyToken(token) c.set('user', user) // Type-safe! await next() })

// Request ID middleware const requestId = createMiddleware<{ Variables: Variables }>(async (c, next) => { c.set('requestId', crypto.randomUUID()) await next() })

app.use(requestId) app.use('/api/*', auth)

app.get('/api/profile', (c) => { const user = c.get('user') // Type: { id, email, role } const reqId = c.get('requestId') // Type: string return c.json({ user, requestId: reqId }) })

Built-in Middleware

CORS

import { cors } from 'hono/cors'

// Simple - allow all origins app.use('/api/*', cors())

// Configured app.use('/api/*', cors({ origin: ['https://example.com', 'https://app.example.com'], allowMethods: ['GET', 'POST', 'PUT', 'DELETE'], allowHeaders: ['Content-Type', 'Authorization'], exposeHeaders: ['X-Total-Count'], credentials: true, maxAge: 86400 }))

// Dynamic origin app.use('/api/*', cors({ origin: (origin) => { return origin.endsWith('.example.com') ? origin : 'https://example.com' } }))

Bearer Auth

import { bearerAuth } from 'hono/bearer-auth'

// Simple token validation app.use('/api/*', bearerAuth({ token: 'my-secret-token' }))

// Multiple tokens app.use('/api/*', bearerAuth({ token: ['token1', 'token2', 'token3'] }))

// Custom verification app.use('/api/*', bearerAuth({ verifyToken: async (token, c) => { const user = await validateJWT(token) if (user) { c.set('user', user) return true } return false } }))

Basic Auth

import { basicAuth } from 'hono/basic-auth'

app.use('/admin/*', basicAuth({ username: 'admin', password: 'secret' // pragma: allowlist secret }))

// Multiple users app.use('/admin/*', basicAuth({ verifyUser: (username, password, c) => { return username === 'admin' && password === process.env.ADMIN_PASSWORD } }))

JWT Auth

import { jwt } from 'hono/jwt'

app.use('/api/*', jwt({ secret: 'my-jwt-secret' // pragma: allowlist secret }))

// Access payload in handler app.get('/api/profile', (c) => { const payload = c.get('jwtPayload') return c.json({ userId: payload.sub }) })

// With algorithm app.use('/api/*', jwt({ secret: 'secret', // pragma: allowlist secret alg: 'HS256' }))

Logger

import { logger } from 'hono/logger'

// Default format app.use(logger())

// Custom format app.use(logger((str, ...rest) => { console.log([API] ${str}, ...rest) }))

// Output: <-- GET /api/users // --> GET /api/users 200 12ms

Pretty JSON

import { prettyJSON } from 'hono/pretty-json'

// Add ?pretty to format JSON responses app.use(prettyJSON())

// GET /api/users → {"users":[...]} // GET /api/users?pretty → formatted JSON

Compress

import { compress } from 'hono/compress'

app.use(compress())

// With options app.use(compress({ encoding: 'gzip' // 'gzip' | 'deflate' }))

ETag

import { etag } from 'hono/etag'

app.use(etag())

// Weak ETags app.use(etag({ weak: true }))

Cache

import { cache } from 'hono/cache'

// Cloudflare Workers cache app.use('/static/*', cache({ cacheName: 'my-app', cacheControl: 'max-age=3600' }))

Secure Headers

import { secureHeaders } from 'hono/secure-headers'

app.use(secureHeaders())

// Configured app.use(secureHeaders({ contentSecurityPolicy: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'"] }, xFrameOptions: 'DENY', xXssProtection: '1; mode=block' }))

CSRF Protection

import { csrf } from 'hono/csrf'

app.use(csrf())

// With options app.use(csrf({ origin: ['https://example.com'] }))

Timeout

import { timeout } from 'hono/timeout'

// 5 second timeout app.use('/api/*', timeout(5000))

// Custom error app.use('/api/*', timeout(5000, () => { return new Response('Request timeout', { status: 408 }) }))

Request ID

import { requestId } from 'hono/request-id'

app.use(requestId())

app.get('/', (c) => { const id = c.get('requestId') return c.json({ requestId: id }) })

Advanced Patterns

Conditional Middleware

// Apply middleware based on condition const conditionalAuth = createMiddleware(async (c, next) => { // Skip auth for health checks if (c.req.path === '/health') { return next() }

// Apply auth for everything else const token = c.req.header('Authorization') if (!token) { return c.json({ error: 'Unauthorized' }, 401) }

await next() })

Middleware Composition

import { every, some } from 'hono/combine'

// All middleware must pass const strictAuth = every( bearerAuth({ token: 'secret' }), ipRestriction(['192.168.1.0/24']), rateLimiter({ max: 100 }) )

// Any middleware can pass const flexibleAuth = some( bearerAuth({ token: 'api-key' }), basicAuth({ username: 'user', password: 'pass' }) // pragma: allowlist secret )

app.use('/api/', strictAuth) app.use('/public/', flexibleAuth)

Modifying Responses

const addHeaders = createMiddleware(async (c, next) => { await next()

// Modify response after handler c.res.headers.set('X-Powered-By', 'Hono') c.res.headers.set('X-Request-Id', c.get('requestId')) })

const transformResponse = createMiddleware(async (c, next) => { await next()

// Replace response entirely const originalBody = await c.res.json() c.res = new Response( JSON.stringify({ data: originalBody, timestamp: Date.now() }), c.res ) })

Error Handling in Middleware

import { HTTPException } from 'hono/http-exception'

const safeMiddleware = createMiddleware(async (c, next) => { try { await next() } catch (error) { if (error instanceof HTTPException) { throw error // Re-throw HTTP exceptions }

// Log and convert other errors
console.error('Middleware error:', error)
throw new HTTPException(500, { message: 'Internal error' })

} })

Rate Limiting

// Simple in-memory rate limiter const rateLimiter = (options: { max: number; window: number }) => { const requests = new Map<string, { count: number; reset: number }>()

return createMiddleware(async (c, next) => { const ip = c.req.header('CF-Connecting-IP') || 'unknown' const now = Date.now()

let record = requests.get(ip)

if (!record || now > record.reset) {
  record = { count: 0, reset: now + options.window }
  requests.set(ip, record)
}

record.count++

if (record.count > options.max) {
  c.header('Retry-After', String(Math.ceil((record.reset - now) / 1000)))
  return c.json({ error: 'Rate limit exceeded' }, 429)
}

c.header('X-RateLimit-Limit', String(options.max))
c.header('X-RateLimit-Remaining', String(options.max - record.count))

await next()

}) }

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

Middleware Order Best Practices

const app = new Hono()

// 1. Request ID (first - for tracking) app.use(requestId())

// 2. Logger (early - to log all requests) app.use(logger())

// 3. Security headers app.use(secureHeaders())

// 4. CORS (before auth - for preflight) app.use('/api/*', cors())

// 5. Compression app.use(compress())

// 6. Rate limiting app.use('/api/*', rateLimiter({ max: 100, window: 60000 }))

// 7. Authentication app.use('/api/*', bearerAuth({ verifyToken }))

// 8. Request validation (after auth) app.use('/api/*', validator)

// 9. Routes app.route('/api', apiRoutes)

// 10. Not found handler (last) app.notFound((c) => c.json({ error: 'Not found' }, 404))

Quick Reference

Built-in Middleware

Middleware Import Purpose

cors

hono/cors

Cross-origin requests

bearerAuth

hono/bearer-auth

Bearer token auth

basicAuth

hono/basic-auth

HTTP Basic auth

jwt

hono/jwt

JWT verification

logger

hono/logger

Request logging

prettyJSON

hono/pretty-json

JSON formatting

compress

hono/compress

Response compression

etag

hono/etag

ETag headers

cache

hono/cache

Response caching

secureHeaders

hono/secure-headers

Security headers

csrf

hono/csrf

CSRF protection

timeout

hono/timeout

Request timeout

requestId

hono/request-id

Request ID header

Third-Party Middleware

npm install @hono/zod-validator # Zod validation npm install @hono/graphql-server # GraphQL npm install @hono/swagger-ui # Swagger UI npm install @hono/prometheus # Prometheus metrics npm install @hono/sentry # Sentry error tracking

Related Skills

  • hono-core - Framework fundamentals

  • hono-validation - Request validation with Zod

  • hono-cloudflare - Cloudflare-specific middleware

Version: Hono 4.x Last Updated: January 2025 License: MIT

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

drizzle-orm

No summary provided by upstream source.

Repository SourceNeeds Review
General

pydantic

No summary provided by upstream source.

Repository SourceNeeds Review
General

playwright-e2e-testing

No summary provided by upstream source.

Repository SourceNeeds Review
General

tailwind-css

No summary provided by upstream source.

Repository SourceNeeds Review