From hono-routing
Guides building type-safe Hono APIs with routing, middleware, Zod/Valibot validation, and RPC client type inference. Use for request validation, middleware composition, or RPC errors.
How this skill is triggered — by the user, by Claude, or both
Slash command
/hono-routing:hono-routingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
**Status**: Production Ready ✅
references/common-patterns.mdreferences/middleware-catalog.mdreferences/rpc-guide.mdreferences/setup-guide.mdreferences/top-errors.mdreferences/validation-libraries.mdscripts/check-versions.shtemplates/context-extension.tstemplates/error-handling.tstemplates/middleware-composition.tstemplates/package.jsontemplates/routing-patterns.tstemplates/rpc-client.tstemplates/rpc-pattern.tstemplates/validation-valibot.tstemplates/validation-zod.tsStatus: Production Ready ✅ Last Updated: 2025-11-21 Dependencies: None (framework-agnostic) Latest Versions: [email protected], [email protected], [email protected]
bun add [email protected] # preferred
# or: bun add [email protected]
Why Hono:
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.json({ message: 'Hello Hono!' })
})
export default app
CRITICAL:
c.json(), c.text(), c.html() for responsesres.send() like Express)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 })
})
✅ 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 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
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()
})
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!
})
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()
})
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!
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.
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
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.string().email(),
})),
(c) => {
const data = c.req.valid('json') // Typed!
return c.json(data)
}
)
Load: references/validation-libraries.md
When: Full-stack TypeScript with shared types
Load: references/rpc-guide.md + templates/rpc-pattern.ts
When: Authentication, logging, rate limiting
Load: references/middleware-catalog.md + templates/middleware-composition.ts
When: Share data between middleware and routes
Load: templates/context-extension.ts
Load references/setup-guide.md when:
Load references/top-errors.md when:
Load references/common-patterns.md when:
Load references/middleware-catalog.md when:
Load references/rpc-guide.md when:
Load references/validation-libraries.md when:
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.json({ message: 'Hello' }))
export default app
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
Required:
hono@^4.10.2 - Core frameworkChoose 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| 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:
Verified working projects:
When installing Hono and middleware packages, follow supply chain security best practices:
npm config set ignore-scripts true (or Bun: disabled by default)socket package score npm <pkg> or use socket npm install <pkg> to check packagesLoad the dependency-upgrade skill for full security configuration including Socket CLI integration, cooldown setup, lockfile validation, and CI enforcement.
bun add hono)Questions? Issues?
references/top-errors.md for all 12 errors and solutionsreferences/setup-guide.md for complete setup walkthroughreferences/common-patterns.md for production patternsreferences/middleware-catalog.md for built-in middlewarereferences/rpc-guide.md for type-safe client/servernpx claudepluginhub secondsky/claude-skills --plugin hono-routingGuides Hono app creation, API building, middleware/auth/validation addition, routing, context usage, streaming, WebSocket, CORS, testing, SSG, and multi-runtime deployment including Cloudflare Workers.
Build ultra-fast web APIs and full-stack apps with Hono on edge runtimes like Cloudflare Workers, Deno, Bun, and Node.js.
Builds Hono web applications with routing, middleware, JSX, validation, testing, and streaming. Provides inline API reference and CLI endpoint testing via `npx hono request`.