Hono — Ultra-Fast Web Framework Guide

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Hono is a new-generation framework designed for Edge Computing. It's tiny, fast, and works everywhere — Cloudflare Workers, Bun, Deno, and Node.js.

What is Hono?

Hono is built for the future of computing:

  • Ultra-lightweight: 14KB minified
  • Edge-ready: Runs on Cloudflare Workers
  • Multi-platform: Deno, Bun, Node.js, browsers
  • TypeScript first: Excellent type inference
npm create hono@latest my-app
cd my-app
npm run dev

Basic Server

import { Hono } from "hono";

const app = new Hono();

app.get("/", (c) => c.text("Hello, World!"));

app.post("/users", async (c) => {
  const user = await c.req.json();
  return c.json({ id: 1, ...user }, 201);
});

export default app;

Routing

const app = new Hono();

// Basic routes
app.get("/", (c) => c.text("GET"));
app.post("/", (c) => c.text("POST"));
app.put("/", (c) => c.text("PUT"));
app.delete("/", (c) => c.text("DELETE"));

// Path parameters
app.get("/users/:id", (c) => {
  const id = c.req.param("id");
  return c.json({ id });
});

// Query parameters
app.get("/search", (c) => {
  const q = c.req.query("q");
  return c.json({ query: q });
});

// Regex routes
app.get(/^\/posts\/.+$/, (c) => c.text("Post"));

// Groups
const api = new Hono();
api.get("/users", (c) => c.json([]));
app.route("/api", api);

Middleware

import { Hono } from "hono";
import { logger } from "hono/logger";
import { cors } from "hono/cors";
import { bearerAuth } from "hono/bearer-auth";

const app = new Hono();

// Logging
app.use(logger());

// CORS
app.use(cors());

// Authentication
app.use("/api/*", bearerAuth({ token: "secret" }));

// Custom middleware
app.use(async (c, next) => {
  console.log(`${c.req.method} ${c.req.path}`);
  await next();
});

app.get("/api/protected", (c) => c.json({ data: "secret" }));

export default app;

Handlers and Contexts

const app = new Hono();

// Context object (c) provides access to request and response
app.post("/users", async (c) => {
  // Request
  const body = await c.req.json();
  const headers = c.req.headers();
  const path = c.req.path;
  const url = c.req.url;

  // Response
  return c.json(
    { id: 1, ...body },
    {
      status: 201,
      headers: { "X-Custom": "Header" },
    }
  );
});

// Type-safe params and queries
interface Params {
  id: string;
}

app.get("/users/:id", (c) => {
  const { id } = c.req.param();
  const limit = c.req.query("limit");
  return c.json({ id, limit });
});

Error Handling

import { HTTPException } from "hono/http-exception";

const app = new Hono();

app.get("/users/:id", async (c) => {
  const id = c.req.param("id");
  const user = await getUser(parseInt(id));

  if (!user) {
    throw new HTTPException(404, { message: "User not found" });
  }

  return c.json(user);
});

// Global error handler
app.onError((err, c) => {
  console.error(err);
  return c.json({ error: "Internal Server Error" }, 500);
});

Type Safety

interface User {
  id: number;
  name: string;
  email: string;
}

interface CreateUserInput {
  name: string;
  email: string;
}

const app = new Hono<{
  Bindings: {
    DB: D1Database; // Cloudflare D1
    CACHE: KVNamespace; // Cloudflare KV
  };
}>();

app.post("/users", async (c) => {
  const input = (await c.req.json()) as CreateUserInput;
  const db = c.env.DB;

  const result = await db.prepare("INSERT INTO users (name, email) VALUES (?, ?)").bind(input.name, input.email).run();

  return c.json({ id: result.meta.last_row_id, ...input }, 201);
});

Deployment Targets

Cloudflare Workers

import { Hono } from "hono";

const app = new Hono();

app.get("/", (c) => c.text("Hello from Cloudflare!"));

export default app;
npm install wrangler
wrangler deploy

Bun

bunx create-hono my-app
cd my-app
bun dev

Deno

import { Hono } from "https://deno.land/x/hono/mod.ts";

const app = new Hono();
app.get("/", (c) => c.text("Hello from Deno!"));

Deno.serve(app.fetch);

Node.js

import { Hono } from "hono";
import { serve } from "@hono/node-server";

const app = new Hono();
app.get("/", (c) => c.text("Hello from Node.js!"));

serve({
  fetch: app.fetch,
  port: 3000,
});

Advanced Features

Form Data

app.post("/upload", async (c) => {
  const form = await c.req.parseFormData();
  const file = form.get("file");
  const name = form.get("name");

  return c.json({ uploaded: true, name });
});

File Serving

app.get("/static/:path", serveStatic({ root: "./public" }));

OpenAPI/Swagger Integration

import { openapi } from "@hono/zod-openapi";

const app = openapi();

app.openapi(
  openapi.registry().registerComponent("schemas", "User", {
    type: "object",
    properties: {
      id: { type: "number" },
      name: { type: "string" },
    },
  })
);

Comparison: Hono vs Express vs Fastify

FeatureExpressFastifyHono
Size50KB32KB14KB
Edge ReadyNoNoYes
Cloudflare WorkersNoNoYes
Type SafetyLimitedGoodExcellent
PerformanceGoodExcellentExcellent

FAQ

Q: Should I use Hono for traditional Node.js servers? A: It works, but Express/Fastify are more mature. Use Hono if Edge deployment is your goal.

Q: Is Hono production-ready? A: Yes, many companies use it in production on Cloudflare Workers.

Q: Can I use Hono with databases? A: Yes, works with any database. Cloudflare D1 is native integration.


Hono is the future of lightweight web frameworks. Perfect for Edge Computing and serverless, it's also great for small APIs and microservices anywhere.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro