Why I fell in love with Hono
I wrote APIs in Express for years. It was the obvious starting point for anyone coming from the Node.js world: huge ecosystem, documentation everywhere, middleware for everything. Then came Fastify with its obsession with performance and its real-world schema validation — a real step up.
Then I tried Hono for a small project, almost by chance, and I never looked back.
What is Hono
Hono is an ultra-lightweight web framework written in TypeScript. The name comes from the Japanese 炎 — flame. It’s fast, small, and runs anywhere: Node.js, Deno, Bun, Cloudflare Workers, Vercel Edge Functions, AWS Lambda.
This last part is what makes the difference.
The problem Hono solves
Express and Fastify are tied to Node.js. They work great on a server, but they don’t run on edge runtimes like Cloudflare Workers or Vercel Edge Functions — environments that use standard Web APIs instead of Node APIs.
If you wanted server-side logic on the edge, you had to rewrite everything with different APIs, learn each platform’s quirks, and keep separate codebases.
Hono is built on Web Standard APIs — Request, Response, Headers, URL. The ones the browser already knows. The ones every modern runtime implements.
import { Hono } from "hono";
const app = new Hono();
app.get("/api/hello", (c) => {
return c.json({ message: "hello" });
});
export default app;
This code runs identically on Node.js, Bun, Cloudflare Workers, and Vercel Edge. Zero changes.
What really convinced me
First-class Type Safety
With Express, types were an afterthought — @types/express was a separate package, and middleware broke type inference at every step. With Hono, TypeScript is at the core of the design.
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";
const app = new Hono();
const schema = z.object({
name: z.string().min(1),
age: z.number().int().positive(),
});
app.post("/users", zValidator("json", schema), (c) => {
const { name, age } = c.req.valid("json"); // typed, no cast needed
return c.json({ name, age }, 201);
});
The type of c.req.valid("json") is inferred directly from the Zod schema. If the payload doesn’t validate, Hono responds with 400 before the handler even runs. No validation logic to write by hand.
Composable Middleware without magic
In Express, middleware was a function with four arguments and a next() to call — an implicit contract that led to subtle bugs. In Hono, it’s an async function that uses await next() explicitly and readably:
// Auth middleware
app.use("/api/*", async (c, next) => {
const token = c.req.header("Authorization");
if (!token) return c.json({ error: "unauthorized" }, 401);
await next();
});
The RPC client is a beautiful thing
This feature alone is worth the switch. Hono lets you export your route types and use them in a TypeScript client — no code generation, no OpenAPI, no intermediate steps.
// server.ts
const routes = app.get("/posts/:id", (c) => {
return c.json({ id: c.req.param("id"), title: "Example post" });
});
export type AppType = typeof routes;
// client.ts
import { hc } from "hono/client";
import type { AppType } from "./server";
const client = hc<AppType>("http://localhost:3000");
const res = await client.posts[":id"].$get({ param: { id: "42" } });
const data = await res.json(); // typed end-to-end
TypeScript already knows what every endpoint returns. If you change a type on the server, the client breaks at compile time — not at runtime in production.
Where I use it
Today I use Hono for anything that’s an API or a lightweight backend:
- APIs deployed on Cloudflare Workers (edge, global latency under 50ms)
- Webhook handlers on AWS Lambda
- Prototype and side-project backends on Bun locally
For applications with complex ORMs, job queues, or sockets — I evaluate case by case. But for stateless APIs, Hono has become my default.
Conclusion
Express taught me how a web framework works. Fastify showed me that performance can be designed. Hono made me realize that the runtime shouldn’t be an architectural constraint.
It’s a framework that respects your time: TypeScript works with zero config, the documentation is clear, the APIs are predictable. It never surprises you in the wrong way.
And that, in the end, is all I ask of a tool.