Conventions for building fast, type-safe APIs with Hono on Node.js, Cloudflare Workers, Deno, or Bun, covering routing, middleware, validation, and RPC patterns.
# Hono Conventions
## App Setup
- Create a typed `Hono` app with environment bindings: `const app = new Hono<{ Bindings: Env; Variables: Variables }>()`.
- Define `Env` (platform bindings like KV, D1) and `Variables` (request-scoped context like `user`) as TypeScript interfaces.
- Split the app into feature modules using `new Hono()` sub-apps. Mount with `app.route('/users', usersApp)`.
- Export the `app` object from the entry file; the adapter (Cloudflare, Node, Bun) wraps it at the server entry.
## Routing
- Group related routes in feature files: `src/routes/users.ts`, `src/routes/orders.ts`.
- Use chainable route definition when multiple methods share a path: `app.on(['GET', 'POST'], '/items', handler)`.
- Name path parameters clearly: `:userId`, `:orderId` — not `:id` which is ambiguous.
- Use `app.basePath('/api/v1')` for versioned APIs rather than prefixing every route manually.
## Validation with Zod
- Use `@hono/zod-validator` middleware for all request validation: `zValidator('json', schema)`, `zValidator('param', schema)`, `zValidator('query', schema)`.
- Define request schemas adjacent to routes or in a `schemas/` file per feature.
- Access validated data via `c.req.valid('json')` — this is fully typed; do not use `c.req.json()` for validated routes.
- Return validation errors as 400 with structured JSON. Customize the error response in the `zValidator` hook.
## Context & Variables
- Store request-scoped data (auth user, request ID) with `c.set('key', value)` in middleware and `c.get('key')` in handlers.
- Type variables in the `Hono` generic — do not use untyped `c.get()`.
- Use `c.env` for platform environment bindings (KV, R2, D1, Secrets).
- Middleware that sets variables must call `await next()` and return the middleware result.
## RPC Mode (Hono Client)
- Export route types for client consumption: `export type AppType = typeof app`.
- Use `hc<AppType>(baseUrl)` in the client for end-to-end type safety.
- Ensure all handler return types are explicit `Response` values from helpers like `c.json()`, `c.text()`, `c.redirect()`.
- Define response schemas with Zod and use them in both server handlers and client expectations.
## Middleware
- Use Hono's built-in middleware first: `logger()`, `cors()`, `bearerAuth()`, `cache()`, `compress()`.
- Write custom middleware as factories: `const myMiddleware = (options: Options): MiddlewareHandler => async (c, next) => { ... }`.
- Apply middleware at the app level for global concerns; at route level for specific protection.
- Error handling: use `app.onError((err, c) => c.json({ error: err.message }, 500))` and `app.notFound(c => c.json({ error: 'Not found' }, 404))`.
## Response Helpers
- Always use Hono's response helpers: `c.json()`, `c.text()`, `c.html()`, `c.redirect()`, `c.notFound()`.
- Set explicit status codes: `c.json(data, 201)` for creation, `c.json(null, 204)` for no content.
- For streaming responses, use `streamText()` or `stream()` from `hono/streaming`.
## Cloudflare Workers Specifics
- Use `c.executionCtx.waitUntil()` for background work that should not block the response.
- Use `c.env.CACHE` (KV) or `caches.default` for edge caching.
- Avoid Node.js built-ins that are not available on the Workers runtime.
## Anti-Patterns
- Do not use raw `new Response()` when Hono helpers are available — they ensure correct Content-Type headers.
- Do not import Node.js `http`/`https` in Workers-targeted code.
- Do not put business logic in route handlers — delegate to service functions.
- Do not use `c.req.json()` without validation — always pair with `zValidator`.