Hono is the ultrafast web framework for the edge — built for Cloudflare Workers, Deno, Bun, and Node.js. It's 3x faster than Express and fits in 14KB.
Why Hono?
- Ultrafast — 3x faster than Express, comparable to Elysia
- Tiny — 14KB minified, zero dependencies for core
- Multi-runtime — Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda
- Type-safe — full TypeScript with RPC-like client
- Middleware ecosystem — JWT, CORS, rate limiting, OpenAPI
- JSX support — server-side rendering built in
Quick Start
# Create a new project
npm create hono@latest my-api
# Or install manually
npm install hono
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => c.text("Hello Hono!"));
app.get("/api/users", (c) => {
return c.json([
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
]);
});
app.post("/api/users", async (c) => {
const body = await c.req.json();
return c.json({ id: 3, ...body }, 201);
});
export default app;
Routing
const app = new Hono();
// Path parameters
app.get("/users/:id", (c) => {
const id = c.req.param("id");
return c.json({ id, name: "Alice" });
});
// Query parameters
app.get("/search", (c) => {
const q = c.req.query("q");
const page = c.req.query("page") || "1";
return c.json({ query: q, page });
});
// Wildcard
app.get("/files/*", (c) => {
const path = c.req.path;
return c.text(`Serving: ${path}`);
});
// Method chaining
app.route("/api/v1")
.get("/users", listUsers)
.post("/users", createUser)
.get("/users/:id", getUser)
.put("/users/:id", updateUser)
.delete("/users/:id", deleteUser);
Middleware
import { Hono } from "hono";
import { cors } from "hono/cors";
import { jwt } from "hono/jwt";
import { logger } from "hono/logger";
import { rateLimiter } from "hono/rate-limiter";
import { secureHeaders } from "hono/secure-headers";
const app = new Hono();
// Global middleware
app.use("*", logger());
app.use("*", secureHeaders());
app.use("*", cors({ origin: "https://myapp.com" }));
// Route-specific middleware
app.use("/api/*", jwt({ secret: "my-secret" }));
// Custom middleware
app.use("/api/*", async (c, next) => {
const start = Date.now();
await next();
const duration = Date.now() - start;
c.header("X-Response-Time", `${duration}ms`);
});
Validation (Zod Integration)
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";
const app = new Hono();
const createUserSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
age: z.number().min(18).optional(),
});
app.post(
"/users",
zValidator("json", createUserSchema),
(c) => {
const data = c.req.valid("json");
// data is fully typed: { name: string, email: string, age?: number }
return c.json({ user: data }, 201);
}
);
// Query validation
const searchSchema = z.object({
q: z.string().min(1),
page: z.coerce.number().default(1),
limit: z.coerce.number().default(10),
});
app.get(
"/search",
zValidator("query", searchSchema),
(c) => {
const { q, page, limit } = c.req.valid("query");
return c.json({ query: q, page, limit });
}
);
RPC Client (Type-Safe API Calls)
// server.ts
const app = new Hono()
.get("/users", (c) => c.json([{ id: 1, name: "Alice" }]))
.post("/users", zValidator("json", createUserSchema), (c) => {
return c.json({ id: 2, ...c.req.valid("json") }, 201);
});
export type AppType = typeof app;
// client.ts
import { hc } from "hono/client";
import type { AppType } from "./server";
const client = hc<AppType>("http://localhost:3000");
// Full type safety + autocomplete!
const users = await client.users.$get();
const data = await users.json(); // typed as { id: number, name: string }[]
const newUser = await client.users.$post({
json: { name: "Bob", email: "bob@example.com" },
});
JSX (Server-Side Rendering)
import { Hono } from "hono";
import { html } from "hono/html";
const app = new Hono();
const Layout = ({ children }: { children: any }) => html`
<!DOCTYPE html>
<html>
<head><title>Hono App</title></head>
<body>${children}</body>
</html>
`;
app.get("/", (c) => {
return c.html(
<Layout>
<h1>Hello from Hono!</h1>
<p>Server-rendered HTML</p>
</Layout>
);
});
Deploy Everywhere
// Cloudflare Workers (default)
export default app;
// Node.js
import { serve } from "@hono/node-server";
serve({ fetch: app.fetch, port: 3000 });
// Deno
Deno.serve(app.fetch);
// Bun
export default { fetch: app.fetch, port: 3000 };
// AWS Lambda
import { handle } from "hono/aws-lambda";
export const handler = handle(app);
Hono vs Express vs Fastify vs Elysia
| Feature | Hono | Express | Fastify | Elysia |
|---|---|---|---|---|
| Size | 14KB | 200KB+ | 100KB+ | 50KB |
| Speed | Very fast | Slow | Fast | Fastest |
| TypeScript | Native | @types | Native | Native |
| Multi-runtime | Yes (5+) | Node only | Node only | Bun only |
| Validation | Zod plugin | Manual | Ajv | Built-in |
| RPC client | Built-in | No | No | Eden Treaty |
| JSX | Built-in | EJS/Pug | No | No |
Need to scrape data from any website and get it in structured JSON? Check out my web scraping tools on Apify — no coding required, results in minutes.
Have a custom data extraction project? Email me at spinov001@gmail.com — I build tailored scraping solutions for businesses.
Top comments (0)