Back to Skills
Hono Routing
Type-safe Hono APIs with routing, middleware, RPC. Use for request validation, Zod/Valibot validators, or encountering middleware type inference, validation hook, RPC errors.
api
By secondsky
Skill Content
# Hono Routing & Middleware
**Status**: Production Ready ✅
**Last Updated**: 2025-11-21
**Dependencies**: None (framework-agnostic)
**Latest Versions**: hono@4.10.6, zod@4.1.12, valibot@1.1.0
---
## Quick Start (5 Minutes)
### Install
```bash
bun add hono@4.10.6 # preferred
# or: bun add hono@4.10.6
```
**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
```typescript
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
```bash
bun add zod@4.1.12 @hono/zod-validator@0.7.4
```
```typescript
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
```typescript
// ❌ 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)
```typescript
// ❌ 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
```typescript
// ❌ 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
```typescript
// ❌ 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<AppType>
```typescript
// 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**:
```typescript
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**:
```typescript
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
app.post('/user',
zValidator('json', z.object({
name: z.string(),
email: z.string().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
```typescript
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.json({ message: 'Hello' }))
export default app
```
### Production Configuration
```typescript
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.ts** - RPC client usage
- **package.json** - Dependencies configuration
---
## Dependencies
**Required**:
- `hono@^4.10.2` - Core framework
**Choose ONE validator** (recommended):
- `zod@^4.1.12` + `@hono/zod-validator@^0.7.4` (most popular)
- `valibot@^1.1.0` + `@hono/valibot-validator@^0.5.3` (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)
**Optional**:
- `@hono/node-server` - Node.js adapter
- `@cloudflare/workers-types` - TypeScript types for Workers
---
## Official Documentation
- **Hono**: https://hono.dev
- **GitHub**: https://github.com/honojs/hono (17.8k ⭐)
- **API Reference**: https://hono.dev/docs/api/hono
- **Routing**: https://hono.dev/docs/api/routing
- **Middleware**: https://hono.dev/docs/guides/middleware
- **Validation**: https://hono.dev/docs/guides/validation
- **RPC**: https://hono.dev/docs/guides/rpc
- **Examples**: https://github.com/honojs/hono/tree/main/examples
---
## 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 |
**Recommendation**:
- **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**:
1. **Cloudflare Workers API**: https://github.com/honojs/examples/tree/main/cloudflare-workers
2. **Bun REST API**: https://github.com/honojs/examples/tree/main/bun
3. **Deno API**: https://github.com/honojs/examples/tree/main/deno
4. **Node.js API**: https://github.com/honojs/examples/tree/main/nodejs
---
## Complete Setup Checklist
- [ ] Installed Hono (`bun add hono`)
- [ ] Installed validator (Zod, Valibot, ArkType, or Typia)
- [ ] Created basic app with routes
- [ ] Added validation middleware to routes
- [ ] Configured CORS for cross-origin requests
- [ ] Added global error handler (app.onError)
- [ ] Added 404 handler (app.notFound)
- [ ] Configured context types for custom variables
- [ ] Tested routes locally
- [ ] Deployed to target runtime (Cloudflare, Bun, Deno, Node.js)
---
**Questions? Issues?**
1. Check `references/top-errors.md` for all 12 errors and solutions
2. Review `references/setup-guide.md` for complete setup walkthrough
3. See `references/common-patterns.md` for production patterns
4. Check `references/middleware-catalog.md` for built-in middleware
5. See `references/rpc-guide.md` for type-safe client/server
6. Check official docs: https://hono.devHow to use
- Copy the skill content above
- Create a .claude/skills directory in your project
- Save as .claude/skills/claude-skills-hono-routing.md
- Use /claude-skills-hono-routing in Claude Code to invoke this skill