Type-safe Hono APIs with routing, middleware, RPC. Use for request validation, Zod/Valibot validators, or encountering middleware type inference, validation hook, RPC errors.
npx skills add https://github.com/secondsky/claude-skills --skill hono-routing
Status: 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<AppType>
// 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/serverConvert PyTorch AT_DISPATCH macros to AT_DISPATCH_V2 format in ATen C++ code. Use when porting AT_DISPATCH_ALL_TYPES_AND*, AT_DISPATCH_FLOATING_TYPES*, or other dispatch macros to the new v2 API. For ATen kernel files, CUDA kernels, and native operator implementations.
Write docstrings for PyTorch functions and methods following PyTorch conventions. Use when writing or updating docstrings in PyTorch code.
Statistical models library for Python. Use when you need specific model classes (OLS, GLM, mixed models, ARIMA) with detailed diagnostics, residuals, and inference. Best for econometrics, time series, rigorous inference with coefficient tables. For guided statistical test selection with APA reporting use statistical-analysis.
Answer questions about the AI SDK and help build AI-powered features. Use when developers: (1) Ask about AI SDK functions like generateText, streamText, ToolLoopAgent, embed, or tools, (2) Want to build AI agents, chatbots, RAG systems, or text generation features, (3) Have questions about AI providers (OpenAI, Anthropic, Google, etc.), streaming, tool calling, structured output, or embeddings, (4) Use React hooks like useChat or useCompletion. Triggers on: "AI SDK", "Vercel AI SDK", "generateText", "streamText", "add AI to my app", "build an agent", "tool calling", "structured output", "useChat".
Create an llms.txt file from scratch based on repository structure following the llms.txt specification at https://llmstxt.org/
Use when working directly with the `esm` Python SDK, ESM3 or ESMC model IDs, Forge/Biohub inference clients, or ESMFold2 folding workflows.
Modal is a serverless cloud platform for running Python on demand, including on-demand GPUs. Use when deploying or serving AI/ML models, running GPU-accelerated workloads (training, fine-tuning, inference), serving web endpoints, scheduling batch jobs, or scaling Python code to cloud containers with the Modal SDK.
Use Therapeutics Data Commons through the PyTDC Python package for registry discovery, approved dataset access, task-aware splits, evaluator metrics, benchmark groups, and bounded molecular-oracle workflows.
Take secondsky/hono-routing from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npm.
Without those the skill loads but fails at the first command.