Overview Install Files SecuritySummary Type-safe Hono APIs with routing, middleware, RPC. Use for request validation, Zod/Valibot validators, or encountering middleware type inference, validation hook, RPC errors.
Hono Routing & Middleware
Status : Production Ready ✅
Last Updated : 2025-11-21
Dependencies : None (framework-agnostic)
Latest Versions : [email protected] , [email protected] , [email protected]
Quick Start (5 Minutes)
Install
bun add [email protected] # preferred
# or: bun add [email protected]
Why Hono:
Fast : Built on Web Standards, runs on any JavaScript runtime
Lightweight : ~10KB, no dependencies
Type-safe : Full TypeScript support with type inference
Flexible : Works on Cloudflare Workers, Deno, Bun, Node.js, Vercel
Basic App
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.json({ message: 'Hello Hono!' })
})
export default app
CRITICAL:
Use c.json(), c.text(), c.html() for responses
Return the response (don't use res.send() like Express)
Export app for runtime
Add Validation
bun add [email protected] @hono/[email protected]
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const schema = z.object({
name: z.string(),
age: z.number(),
})
app.post('/user', zValidator('json', schema), (c) => {
const data = c.req.valid('json')
return c.json({ success: true, data })
})
Critical Rules
Always Do
✅ Return responses from handlers (c.json, c.text, c.html, etc.)
✅ Use c.req.valid('source') after validation middleware to get typed data
✅ Export app for deployment (Cloudflare Workers, Bun, Deno, Node.js)
✅ Use validation middleware (zValidator, vValidator) for type-safe request data
✅ Call await next() in middleware to pass control to next handler
✅ Use HTTPException for expected errors (returns proper HTTP status)
✅ Use template tag validators (zValidator, vValidator) not hooks
✅ Define context types for custom variables (Hono<{ Variables: { ... } }>)
✅ Use sub-apps (app.route()) for organizing large APIs
✅ Type your RPC routes (export type AppType = typeof routes) for client
Never Do ❌ Never forget to return response from handlers
❌ Never use req.json() directly without validation - use c.req.valid()
❌ Never mix validation hooks with middleware - use middleware only
❌ Never forget await next() in middleware - breaks middleware chain
❌ Never use res.send() - not available (use c.json(), c.text(), etc.)
❌ Never skip error handling - use app.onError() for global handler
❌ Never access unvalidated data after validation middleware
❌ Never use blocking operations in middleware - breaks async chain
❌ Never hardcode origins in CORS - use environment variables
❌ Never skip type exports for RPC - client won't have types
Top 5 Errors (See references/top-errors.md for all 12)
Error #1: Middleware Response Not Typed Problem : Middleware returns response but route handler still executes
Solution : Don't return from middleware if you want chain to continue - only set variables
// ❌ Wrong - breaks chain
app.use('*', (c) => {
return c.json({ error: 'Unauthorized' }, 401)
})
// ✅ Correct - throw HTTPException instead
app.use('*', (c, next) => {
if (!isAuthorized) {
throw new HTTPException(401, { message: 'Unauthorized' })
}
await next()
})
Error #2: Validation Hook vs Middleware Confusion Problem : Using validation hooks instead of middleware
Solution : Always use middleware validators (zValidator, vValidator)
// ❌ Wrong - hooks deprecated
app.post('/user', (c) => {
const data = c.req.json<User>() // No runtime validation!
})
// ✅ Correct - middleware with runtime validation
app.post('/user', zValidator('json', schema), (c) => {
const data = c.req.valid('json') // Validated & typed!
})
Error #3: Missing await next() in Middleware Problem : Middleware doesn't call next(), breaking chain
Solution : Always call await next() unless returning early
// ❌ Wrong - chain broken
app.use('*', (c) => {
console.log('Log')
// Missing await next()!
})
// ✅ Correct
app.use('*', async (c, next) => {
console.log('Log')
await next()
})
Error #4: Context Variable Type Inference Problem : c.get() and c.set() not typed
Solution : Define Variables type in Hono constructor
// ❌ Wrong - no types
const app = new Hono()
c.set('user', { id: '123' }) // Not typed
const user = c.get('user') // any
// ✅ Correct - typed
type Variables = {
user: { id: string; name: string }
}
const app = new Hono<{ Variables: Variables }>()
c.set('user', { id: '123', name: 'Alice' })
const user = c.get('user') // Fully typed!
Error #5: RPC Type Inference Not Working Problem : Client doesn't have types from server routes
Solution : Export AppType and use hc
// Server
const routes = app.get('/users', (c) => c.json([]))
export type AppType = typeof routes // Export this!
// Client
import { hc } from 'hono/client'
import type { AppType } from './server'
const client = hc<AppType>('http://localhost:8787') // Fully typed!
Load references/top-errors.md for all 12 errors with detailed solutions.
Common Use Cases
Use Case 1: Basic REST API When : Simple CRUD operations
Quick Pattern :
app.get('/users', (c) => c.json({ users: [] }))
app.post('/users', (c) => c.json({ created: true }))
app.get('/users/:id', (c) => c.json({ user: {} }))
app.put('/users/:id', (c) => c.json({ updated: true }))
app.delete('/users/:id', (c) => c.json({ deleted: true }))
Load : references/setup-guide.md → Complete Example
Use Case 2: Request Validation (Zod) When : Need type-safe request validation
Quick Pattern :
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
app.post('/user',
zValidator('json', z.object({
name: z.string(),
email: z.email(),
})),
(c) => {
const data = c.req.valid('json') // Typed!
return c.json(data)
}
)
Load : references/validation-libraries.md
Use Case 3: Type-Safe RPC When : Full-stack TypeScript with shared types
Load : references/rpc-guide.md + templates/rpc-pattern.ts
Use Case 4: Middleware Composition When : Authentication, logging, rate limiting
Load : references/middleware-catalog.md + templates/middleware-composition.ts
Use Case 5: Custom Context Variables When : Share data between middleware and routes
Load : templates/context-extension.ts
When to Load References Load references/setup-guide.md when :
User needs complete setup walkthrough
User asks about deployment to different runtimes
User needs CRUD API example
User wants to try alternative validators (Valibot, ArkType, Typia)
Load references/top-errors.md when :
Encountering any of the 12 documented errors
User has middleware type issues
User confused about validation hooks vs middleware
User needs troubleshooting or debugging
Load references/common-patterns.md when :
User asks for code examples or best practices
User needs route grouping, error handling, file upload patterns
User wants streaming, WebSocket, or pagination examples
Load references/middleware-catalog.md when :
User needs built-in middleware (cors, logger, jwt, cache, compress, etag)
User wants to create custom middleware
User asks about authentication or authorization
Load references/rpc-guide.md when :
User building full-stack TypeScript app
User wants type-safe client/server communication
User asks about hono/client or RPC patterns
Load references/validation-libraries.md when :
User comparing Zod vs Valibot vs ArkType vs Typia
User needs validation examples for each library
User asks about performance or bundle size
Configuration Reference
Minimal Configuration import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.json({ message: 'Hello' }))
export default app
Production Configuration import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { logger } from 'hono/logger'
import { HTTPException } from 'hono/http-exception'
type Variables = {
user: { id: string; name: string }
requestId: string
}
const app = new Hono<{ Variables: Variables }>()
// Global middleware
app.use('*', logger())
app.use('*', async (c, next) => {
c.set('requestId', crypto.randomUUID())
await next()
})
app.use('*', cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
credentials: true,
}))
// Routes
app.route('/api', apiRoutes)
// Global error handler
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json(
{ error: err.message },
err.status
)
}
console.error(err)
return c.json(
{ error: 'Internal Server Error' },
500
)
})
// 404 handler
app.notFound((c) => {
return c.json({ error: 'Not Found' }, 404)
})
export default app
Using Bundled Resources
References (references/)
setup-guide.md - Complete 6-step setup (install → deploy)
top-errors.md - All 12 errors with solutions
common-patterns.md - 7 production patterns (RPC, middleware, error handling, file upload)
middleware-catalog.md - Built-in middleware reference (cors, logger, jwt, cache)
rpc-guide.md - Type-safe RPC client/server guide
validation-libraries.md - Comparison of Zod, Valibot, ArkType, Typia
Templates (templates/)
routing-patterns.ts - Route examples (params, query, wildcard, grouping)
validation-zod.ts - Zod validation examples
validation-valibot.ts - Valibot validation examples
middleware-composition.ts - Auth, rate limiting, logging middleware
error-handling.ts - HTTPException and global error handler
context-extension.ts - Custom context variables
rpc-pattern.ts - RPC server setup
rpc-client.tsx - RPC client usage
package.json - Dependencies configuration
Dependencies
hono@^4.12.12 - Core framework
Choose ONE validator (recommended):
zod@^4.3.6 + @hono/zod-validator@^0.7.4 (most popular)
valibot@^1.1.0 + @hono/valibot-validator@^0.6.1 (smaller bundle)
arktype@^2.0.0 + @hono/arktype-validator@^0.1.0 (fastest runtime)
typia@^7.0.0 + @hono/typia-validator@^0.1.0 (compile-time validation)
@hono/node-server - Node.js adapter
@cloudflare/workers-types - TypeScript types for Workers
Official Documentation
Comparison: Hono vs Alternatives Feature Hono Express Fastify Size ~10KB ~200KB ~100KB TypeScript ✅ Native ⚠️ Types ✅ Native Type Inference ✅ Full ❌ No ⚠️ Limited RPC ✅ Built-in ❌ No ❌ No Edge Runtime ✅ Yes ❌ No ❌ No Validation ✅ Plugin ⚠️ Manual ✅ Plugin Speed Very Fast Fast Very Fast
Use Hono if : TypeScript, edge runtime, full type inference, small bundle
Use Express if : Legacy Node.js app, large ecosystem needed
Use Fastify if : Node.js only, need fastest Node.js framework
Production Examples Verified working projects :
Secure Installation When installing Hono and middleware packages, follow supply chain security best practices:
Block post-install scripts — npm config set ignore-scripts true (or Bun: disabled by default)
Cooldown period — Wait 7 days for new package versions to be vetted by the community
Audit before installing — Run socket package score npm <pkg> or use socket npm install <pkg> to check packages
Load the dependency-upgrade skill for full security configuration including Socket CLI integration, cooldown setup, lockfile validation, and CI enforcement.
Complete Setup Checklist
Check references/top-errors.md for all 12 errors and solutions
Review references/setup-guide.md for complete setup walkthrough
See references/common-patterns.md for production patterns
Check references/middleware-catalog.md for built-in middleware
See references/rpc-guide.md for type-safe client/server
Check official docs: https://hono.dev