Hono Basics
10 examples to build APIs with Hono on Node.js - 7 basic and 3 intermediate.
Prerequisites
mkdir hono-api && cd hono-api
npm init -y
npm pkg set type=module
npm install hono @hono/node-server
npm install -D typescript@5.6 tsxFor runtime portability decisions, see Hono on Node vs Edge.
Basic Examples
1. Hello World on Node
import { Hono } from "hono";
import { serve } from "@hono/node-server";
const app = new Hono();
app.get("/", (c) => c.text("Hello from Hono\n"));
serve({ fetch: app.fetch, port: 3000 });cis the Context object with helpers for response typesapp.fetchis a Web Standardfetchhandler@hono/node-serverbridges Hono to Node HTTP
2. JSON Response
import { Hono } from "hono";
const app = new Hono();
app.get("/users", (c) => {
return c.json([{ id: 1, name: "Ada Lovelace" }]);
});c.json()setsContent-Type: application/json- Return the Response directly from handlers
3. Route Parameters and Query
import { Hono } from "hono";
const app = new Hono();
app.get("/users/:id", (c) => {
const id = c.req.param("id");
const include = c.req.query("include");
return c.json({ id, include });
});c.req.param()for path paramsc.req.query()for query strings
4. POST with JSON Body
import { Hono } from "hono";
const app = new Hono();
app.post("/users", async (c) => {
const body = await c.req.json<{ name: string; email: string }>();
return c.json({ id: "1", ...body }, 201);
});c.req.json()parses body asynchronously- Status code as second argument to
c.json()
5. Middleware
import { Hono } from "hono";
import { logger } from "hono/logger";
const app = new Hono();
app.use("*", logger());
app.use("/api/*", async (c, next) => {
const start = Date.now();
await next();
c.header("X-Response-Time", `${Date.now() - start}ms`);
});app.use(path, middleware)for path-scoped middlewareawait next()to continue the chain- Built-in
logger()middleware for request logging
6. Route Groups
import { Hono } from "hono";
const users = new Hono();
users.get("/", (c) => c.json([]));
users.get("/:id", (c) => c.json({ id: c.req.param("id") }));
const app = new Hono();
app.route("/users", users);app.route(prefix, subApp)mounts route groups- Each sub-app is an independent Hono instance
7. Error Handling
import { Hono } from "hono";
import { HTTPException } from "hono/http-exception";
const app = new Hono();
app.get("/users/:id", (c) => {
const id = c.req.param("id");
if (id === "999") throw new HTTPException(404, { message: "Not found" });
return c.json({ id });
});
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json({ error: err.message }, err.status);
}
return c.json({ error: "Internal server error" }, 500);
});HTTPExceptionfor operational errors with status codesapp.onError()for centralized error handling
Intermediate Examples
8. Typed Context Variables
import { Hono } from "hono";
import { createMiddleware } from "hono/factory";
type Variables = { userId: string };
const app = new Hono<{ Variables: Variables }>();
const auth = createMiddleware<{ Variables: Variables }>(async (c, next) => {
c.set("userId", "user-42");
await next();
});
app.use("/api/*", auth);
app.get("/api/me", (c) => c.json({ userId: c.get("userId") }));- Generic
Variablestype forc.set()/c.get() createMiddlewarefor typed middleware factories
9. CORS and Security
import { Hono } from "hono";
import { cors } from "hono/cors";
import { secureHeaders } from "hono/secure-headers";
const app = new Hono();
app.use("*", cors({ origin: "https://app.example.com" }));
app.use("*", secureHeaders());- Built-in CORS and security headers middleware
- No external
helmetdependency needed
10. Validation with Zod
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),
email: z.string().email(),
});
app.post("/users", zValidator("json", schema), (c) => {
const body = c.req.valid("json");
return c.json({ id: "1", ...body }, 201);
});@hono/zod-validatorintegrates Zod with Honoc.req.valid("json")returns typed, validated data
FAQs
When should I choose Hono over Express or Fastify?
Hono for edge portability, tiny footprint, or Web Standards alignment. Express/Fastify for larger Node ecosystem. See Framework Selection Checklist.
Does Hono work on Node 24?
Yes via @hono/node-server. Same Hono code can deploy to Cloudflare Workers.
Is Hono production-ready?
Yes. Used in production on Cloudflare Workers and Node. Smaller ecosystem than Express/Fastify.
How does Hono compare in size?
~14KB minified vs Express ~200KB+ with middleware. Matters for edge cold starts.
Can I use Hono with TypeScript?
First-class TypeScript support with typed context, validators, and route params.
Related
- Hono on Node vs Edge - runtime ADR
- Koa & Polka - other lightweight options
- Express Basics - mainstream alternative
- Framework Selection Checklist - decision matrix
- Lightweight Frameworks Best Practices - section checklist
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.