Workers with Hono Framework -- Type-Safe APIs
In this tutorial, you'll learn about Workers with Hono Framework. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Hono is a lightweight, ultrafast web framework for Cloudflare Workers that provides type-safe routing, input validation, middleware composition, and a developer experience similar to Express but optimized for the edge runtime.
Why Hono Matters for Workers
Building APIs directly with the Workers fetch handler works for simple cases, but complex applications need routing, parameter Parsing, input validation, error handling, and middleware. Hono provides all of this in a 15KB bundle with zero dependencies. Its TypeScript-first design gives you end-to-end type safety from request Parsing to response construction. With benchmarks showing it handles 50,000+ requests per second on Workers, Hono is the most popular framework in the Cloudflare Workers ecosystem. Combined with JavaScript runtime features, Hono makes edge API development as productive as backend frameworks like Express or Fastify.
Real-world use: A REST API for a note-taking application serves 10,000 users from the edge using Hono with Zod validation, JWT authentication middleware, and Workers KV for storage -- all deployed globally with zero cold starts.
Hono Application Architecture
flowchart LR
R[HTTP Request] --> H[Hono Router]
H --> M[Middleware chain]
M --> A[Auth middleware]
M --> L[Logger middleware]
M --> C[CORS middleware]
A --> V[Validator]
V --> P[Route handler]
P --> RV[Response]
H --> E[Error handler]
E --> RV
style H fill:#f90,color:#fff
style A fill:#f90,color:#fff
style V fill:#f90,color:#fff
Setting Up a Basic Hono Worker
Initialize a Hono project and create your first typed endpoint.
npm create hono@latest my-api
cd my-api
npm install
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello from Hono on Workers!'));
app.get('/api/health', (c) => c.json({ status: 'ok', timestamp: Date.now() }));
export default app;
Expected output: GET / returns Hello from Hono on Workers! as plain text. GET /api/health returns {"status": "ok", "timestamp": 1719000000000} as JSON. Hono automatically handles JSON Serialization and content-type headers.
Type-Safe Route Parameters and Validation
Hono integrates with Zod for runtime validation with TypeScript type inference.
import { Hono } from 'hono';
import { z } from 'zod';
import { zValidator } from '@hono/zod-validator';
const app = new Hono();
const UserSchema = z.object({
name: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().int().min(0).max(150).optional()
});
app.post('/api/users', zValidator('json', UserSchema), (c) => {
const user = c.req.valid('json');
return c.json({ created: true, user: { name: user.name, email: user.email } }, 201);
});
app.get('/api/users/:id', (c) => {
const id = c.req.param('id');
return c.json({ userId: id, profile: `Profile for user ${id}` });
});
export default app;
Expected output: POST /api/users with {"name": "Alice", "email": "alice@example.com"} returns {"created": true, "user": {"name": "Alice", "email": "alice@example.com"}} with status 201. An invalid payload like {"name": "A"} returns a 400 error with Zod validation details.
Middleware Composition
Compose reusable middleware for authentication, logging, and CORS.
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { bearerAuth } from 'hono/bearer-auth';
const app = new Hono();
app.use('*', logger());
app.use('/api/*', cors({ origin: 'https://myapp.com', credentials: true }));
const token = 'secret-token-123';
app.use('/api/admin/*', bearerAuth({ token }));
app.get('/api/public', (c) => c.json({ message: 'Public endpoint' }));
app.get('/api/admin/dashboard', (c) => c.json({ secret: 'Admin data' }));
export default app;
Expected output: GET /api/public returns the public message. GET /api/admin/dashboard without an Authorization: Bearer secret-token-123 header returns a 401 Unauthorized. All requests are logged via the logger middleware. CORS headers are set on all /api/* routes.
Integrating with Workers KV
Hono makes it easy to pass environment bindings like KV into route handlers.
import { Hono } from 'hono';
type Bindings = {
MY_KV: KVNamespace;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get('/kv/:key', async (c) => {
const key = c.req.param('key');
const value = await c.env.MY_KV.get(key);
if (value === null) {
return c.json({ error: 'Key not found' }, 404);
}
return c.json({ key, value });
});
app.put('/kv/:key', async (c) => {
const key = c.req.param('key');
const body = await c.req.text();
await c.env.MY_KV.put(key, body);
return c.json({ stored: true, key }, 201);
});
app.delete('/kv/:key', async (c) => {
const key = c.req.param('key');
await c.env.MY_KV.delete(key);
return c.json({ deleted: true, key });
});
export default app;
Expected output: GET /kv/greeting reads from KV and returns the value. PUT /kv/greeting with body Hello stores it. DELETE /kv/greeting removes it. The Bindings type provides full type safety for environment variables throughout the application.
Common Errors
| Error | Cause | Fix |
|---|---|---|
Cannot find module 'hono' |
Hono not installed | Run npm install hono in the project directory |
Type 'string' is not assignable to type 'number' |
Zod schema mismatch | Ensure request payload types match the Zod schema definition |
Bearer token missing |
No Authorization header | Include Authorization: Bearer <token> in request headers |
c.req.valid is not a function |
Validator middleware not applied | Add zValidator or another validator to the route chain |
env is undefined |
Missing Bindings type on Hono instance | Add { Bindings: YourBindings } generic type to new Hono() |
Practice Questions
- How does Hono's
zValidatormiddleware provide both runtime validation and TypeScript type inference? - What is the purpose of the
Bindingsgeneric type when creating a Hono application for Workers? - How does Hono's middleware composition differ from the raw fetch event approach in plain Workers?
FAQ
{{< faq "Is Hono compatible with all Cloudflare Workers features including D1 and R2?">}}
Yes, Hono supports all Workers runtime APIs including D1, R2, Queues, Durable Objects, and KV. You pass bindings through the Bindings generic type and access them via c.env in route handlers.
{{< /faq >}}
Summary
Hono brings Express-like productivity to Cloudflare Workers with type-safe routing, Zod validation, middleware composition, and native Workers binding support. Its 15KB footprint, zero dependencies, and 50,000+ requests per second performance make it the leading framework for edge API development. TypeScript integration catches errors at compile time while Zod validation catches them at runtime. Doda Browser uses Hono to power its privacy settings API, serving configuration endpoints globally with full type safety and input validation. Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro -- security-first tools for the modern web.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro