Claude
Skills
Sign in
Back

hono-routing

Included with Lifetime
$97 forever

Type-safe Hono APIs with routing, middleware, RPC. Use for request validation, Zod/Valibot validators, or encountering middleware type inference, validation hook, RPC errors.

Generalscripts

What this skill does

# 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

```bash
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

```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 [email protected] @hono/[email protected]
```

```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()

ap

Related in General