Building REST APIs with Hono: The Ultra-Fast Web Framework
Build high-performance REST APIs with Hono, the lightweight TypeScript framework that runs on Bun, Deno, Node.js, and Cloudflare Workers. Covers routing,...
Why Hono?
Hono (meaning "flame" in Japanese) is a small, ultrafast web framework for the Edge and beyond. At ~14KB, it is one of the smallest web frameworks available, yet it supports middleware, routing, validation, and OpenAPI generation.
API gateway pattern: a single entry point handles auth, rate limiting, and routing to backend services.
What makes Hono special:
- Multi-runtime: Works on Bun, Deno, Node.js, Cloudflare Workers, AWS Lambda
- Type-safe: Full TypeScript support with type inference
- Fast: Benchmarks show it outperforming Express by 5-10x
- Standards-based: Uses Web Standards API (Request/Response)
Getting Started
# Create a new Hono project with Bun
bun create hono my-api
cd my-api
# Or with Node.js
npm create hono@latest my-api
Basic API
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { prettyJSON } from "hono/pretty-json";
const app = new Hono();
// Middleware
app.use("*", logger());
app.use("*", cors());
app.use("*", prettyJSON());
// Routes
app.get("/", (c) => {
return c.json({ message: "Welcome to the API", version: "1.0.0" });
});
app.get("/health", (c) => {
return c.json({ status: "healthy", uptime: process.uptime() });
});
export default app;
Get more insights on Tutorials
Join 2,000+ engineers who get our weekly deep-dives. No spam, unsubscribe anytime.
CRUD API with Validation
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";
const app = new Hono();
// Validation schemas
const createUserSchema = z.object({
name: z.string().min(2).max(100),
email: z.string().email(),
role: z.enum(["admin", "user", "viewer"]).default("user"),
});
const updateUserSchema = createUserSchema.partial();
// In-memory store (replace with database)
let users: Array<{ id name email role }> = [];
let nextId = 1;
// List users
app.get("/api/users", (c) => {
const page = Number(c.req.query("page") || "1");
const limit = Number(c.req.query("limit") || "10");
const start = (page - 1) * limit;
return c.json({
data: users.slice(start, start + limit),
total: users.length,
page,
limit,
});
});
// Get single user
app.get("/api/users/:id", (c) => {
const user = users.find((u) => u.id === c.req.param("id"));
if (!user) {
return c.json({ error: "User not found" }, 404);
}
return c.json(user);
});
// Create user
app.post("/api/users", zValidator("json", createUserSchema), (c) => {
const body = c.req.valid("json");
const user = { id: String(nextId++), ...body };
users.push(user);
return c.json(user, 201);
});
// Update user
app.put("/api/users/:id", zValidator("json", updateUserSchema), (c) => {
const id = c.req.param("id");
const body = c.req.valid("json");
const index = users.findIndex((u) => u.id === id);
if (index === -1) {
return c.json({ error: "User not found" }, 404);
}
users[index] = { ...users[index], ...body };
return c.json(users[index]);
});
// Delete user
app.delete("/api/users/:id", (c) => {
const id = c.req.param("id");
const index = users.findIndex((u) => u.id === id);
if (index === -1) {
return c.json({ error: "User not found" }, 404);
}
users.splice(index, 1);
return c.json({ message: "User deleted" });
});
export default app;
Middleware
Authentication Middleware
import { Hono } from "hono";
import { bearerAuth } from "hono/bearer-auth";
import { jwt } from "hono/jwt";
const app = new Hono();
// Simple bearer token
app.use("/api/*", bearerAuth({ token: "my-secret-token" }));
// JWT authentication
app.use("/api/*", jwt({ secret: "your-jwt-secret" }));
// Custom auth middleware
const requireRole = (role) => {
return async (c: any, next: any) => {
const payload = c.get("jwtPayload");
if (payload.role !== role) {
return c.json({ error: "Forbidden" }, 403);
}
await next();
};
};
app.get("/api/admin", requireRole("admin"), (c) => {
return c.json({ message: "Admin area" });
});
Microservices architecture: independent services communicate through an API gateway and event bus.
Error Handling
import { Hono } from "hono";
import { HTTPException } from "hono/http-exception";
const app = new Hono();
// Global error handler
app.onError((err, c) => {
if (err instanceof HTTPException) {
return c.json({ error: err.message }, err.status);
}
console.error(err);
return c.json({ error: "Internal Server Error" }, 500);
});
// 404 handler
app.notFound((c) => {
return c.json({ error: "Not Found", path: c.req.path }, 404);
});
Rate Limiting
import { Hono } from "hono";
import { rateLimiter } from "hono-rate-limiter";
const app = new Hono();
const limiter = rateLimiter({
windowMs: 60 * 1000, // 1 minute
limit: 100, // 100 requests per window
standardHeaders: "draft-6",
keyGenerator: (c) => c.req.header("x-forwarded-for") || "unknown",
});
app.use("/api/*", limiter);
Database Integration
import { Hono } from "hono";
import { drizzle } from "drizzle-orm/node-postgres";
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
import { eq } from "drizzle-orm";
import pg from "pg";
// Schema
const users = pgTable("users", {
id: serial("id").primaryKey(),
name: text("name").notNull(),
email: text("email").notNull().unique(),
createdAt: timestamp("created_at").defaultNow(),
});
// Database connection
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
const db = drizzle(pool);
const app = new Hono();
app.get("/api/users", async (c) => {
const result = await db.select().from(users);
return c.json(result);
});
app.get("/api/users/:id", async (c) => {
const id = Number(c.req.param("id"));
const result = await db.select().from(users).where(eq(users.id, id));
if (result.length === 0) {
return c.json({ error: "Not found" }, 404);
}
return c.json(result[0]);
});
export default app;
Deployment
Bun
// src/index.ts
import app from "./app";
export default {
port: process.env.PORT || 3000,
fetch: app.fetch,
};
bun run src/index.ts
Docker
Free Resource
Free Cloud Architecture Checklist
A 47-point checklist covering security, scalability, cost optimization, and disaster recovery for production cloud environments.
FROM oven/bun:1-alpine
WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install --production
COPY src ./src
EXPOSE 3000
CMD ["bun", "run", "src/index.ts"]
A well-structured configuration file is the foundation of reproducible infrastructure.
Benchmarks
On a simple JSON response endpoint:
| Framework | Requests/sec | Latency (p99) |
|---|---|---|
| Hono (Bun) | 120,000 | 0.8ms |
| Elysia (Bun) | 115,000 | 0.9ms |
| Fastify (Node) | 55,000 | 2.1ms |
| Express (Node) | 15,000 | 8.5ms |
Hono on Bun is 8x faster than Express.
At TechSaaS, we use Hono for lightweight API services that need to be fast and portable. Its multi-runtime support means we can develop locally with Bun and deploy to Cloudflare Workers or Docker without changing code.
Need help building APIs? Contact [email protected].
Related Service
Cloud Solutions
Let our experts help you build the right technology strategy for your business.
Need help with tutorials?
TechSaaS provides expert consulting and managed services for cloud infrastructure, DevOps, and AI/ML operations.
We Will Build You a Demo Site — For Free
Like it? Pay us. Do not like it? Walk away, zero complaints. You will spend way less than hiring developers or any agency.
No spam. No contracts. Just a free demo.