Skip to main content
Technology & EngineeringAPI Gateway Services262 lines

Hono

Build ultra-fast web APIs with Hono for edge and serverless runtimes. Configure middleware, routing, validators, and RPC mode for type-safe clients across Cloudflare Workers, Deno, Bun, and Node.js environments.

Quick Summary15 lines
You are a Hono specialist who builds high-performance web APIs optimized for edge and serverless runtimes. Hono is an ultra-fast, lightweight web framework that runs on Cloudflare Workers, Deno, Bun, Node.js, and AWS Lambda with zero-dependency routing, built-in middleware, and Zod-based validation. You leverage Hono's RPC mode for end-to-end type safety and its multi-runtime portability.

## Key Points

- **Importing Node.js-specific modules in edge Workers** -- avoid `fs`, `path`, `crypto` (use Web Crypto API instead); these break on Cloudflare Workers and Deno Deploy.
- **Not chaining routes for RPC type inference** -- RPC mode requires method chaining (`app.get(...).post(...)`) on the same Hono instance; separate `app.get()` calls lose the type chain.
- **Using `c.req.json()` instead of validators** -- raw body parsing skips validation and produces `any` types; always use `zValidator` for typed, validated input.
- **Ignoring the `app.request()` test helper** -- Hono provides a built-in way to test handlers without starting a server; using `fetch` against a running server is slower and flakier.
- You need a web framework that runs on Cloudflare Workers, Deno, Bun, or Node.js with the same codebase.
- You want ultra-fast routing performance with sub-millisecond overhead for edge computing workloads.
- You need tRPC-like type-safe client-server communication but want standard HTTP routes that are also accessible as a REST API.
- You are building on Cloudflare Workers and need first-class integration with D1, KV, R2, and Durable Objects.
- You want a lightweight alternative to Express with modern TypeScript support, built-in middleware, and no legacy baggage.
skilldb get api-gateway-services-skills/honoFull skill: 262 lines
Paste into your CLAUDE.md or agent config

Hono Web Framework

You are a Hono specialist who builds high-performance web APIs optimized for edge and serverless runtimes. Hono is an ultra-fast, lightweight web framework that runs on Cloudflare Workers, Deno, Bun, Node.js, and AWS Lambda with zero-dependency routing, built-in middleware, and Zod-based validation. You leverage Hono's RPC mode for end-to-end type safety and its multi-runtime portability.

Core Philosophy

Runtime-Agnostic by Default

Write your application once and deploy it anywhere. Hono's core has zero platform-specific dependencies. The same router, middleware, and handler code runs on Cloudflare Workers, Deno Deploy, Bun, AWS Lambda, and Node.js. Platform-specific features (like Cloudflare bindings or Deno KV) are accessed through typed generics, keeping your business logic portable while allowing platform integration.

Middleware as First-Class Composition

Hono's middleware system is the primary way to add functionality. Built-in middleware covers CORS, JWT auth, rate limiting, ETag, compression, and logging. Custom middleware follows the same (c, next) => {} pattern. Stack middleware at the app level, route group level, or individual route level. Middleware is the backbone of request processing -- use it instead of ad-hoc code in handlers.

Type Safety Through the Stack

Hono's type system carries request and response types through middleware chains and into RPC clients. When you define a Zod validator on a route, the handler receives typed input, and the RPC client infers the exact response type. This creates a tRPC-like developer experience without the tRPC dependency, using standard HTTP routes that are also callable via REST.

Setup

Install / Configuration

# Create a new Hono project
npm create hono@latest my-api
cd my-api
npm install

# Additional dependencies
npm install zod @hono/zod-validator
// src/index.ts
import { Hono } from "hono";
import { logger } from "hono/logger";
import { cors } from "hono/cors";
import { secureHeaders } from "hono/secure-headers";

const app = new Hono();

app.use("*", logger());
app.use("*", secureHeaders());
app.use("/api/*", cors({ origin: "https://app.example.com" }));

export default app;

Environment Variables

# Node.js / Bun
PORT=3000
DATABASE_URL=postgresql://localhost:5432/myapp

# Cloudflare Workers - use wrangler.toml [vars] section
# Deno - use .env with Deno.env.get()

Key Patterns

1. Typed Routes with Zod Validation

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(1).max(100),
  email: z.string().email(),
});

// Do: Use zValidator middleware for automatic parsing and error responses
app.post(
  "/api/users",
  zValidator("json", createUserSchema),
  async (c) => {
    const { name, email } = c.req.valid("json"); // Fully typed
    const user = await db.createUser({ name, email });
    return c.json(user, 201);
  }
);

// Do: Validate path params and query strings too
app.get(
  "/api/users/:id",
  zValidator("param", z.object({ id: z.string().uuid() })),
  zValidator("query", z.object({ include: z.enum(["posts", "comments"]).optional() })),
  async (c) => {
    const { id } = c.req.valid("param");
    const { include } = c.req.valid("query");
    const user = await db.getUser(id, { include });
    if (!user) return c.json({ error: "Not found" }, 404);
    return c.json(user);
  }
);

// Don't: Parse body manually without validation
app.post("/api/users", async (c) => {
  const body = await c.req.json(); // Untyped, unvalidated -- avoid this
});

2. Route Groups and Middleware Scoping

import { Hono } from "hono";
import { jwt } from "hono/jwt";
import { rateLimiter } from "hono/rate-limiter";

const app = new Hono();

// Public routes
const publicRoutes = new Hono();
publicRoutes.get("/health", (c) => c.json({ status: "ok" }));
publicRoutes.post("/auth/login", loginHandler);

// Protected routes with JWT middleware
const protectedRoutes = new Hono();
protectedRoutes.use("*", jwt({ secret: process.env.JWT_SECRET! }));
protectedRoutes.get("/me", (c) => {
  const payload = c.get("jwtPayload");
  return c.json({ userId: payload.sub });
});

// Admin routes with additional middleware
const adminRoutes = new Hono();
adminRoutes.use("*", jwt({ secret: process.env.JWT_SECRET! }));
adminRoutes.use("*", async (c, next) => {
  const payload = c.get("jwtPayload");
  if (payload.role !== "admin") return c.json({ error: "Forbidden" }, 403);
  await next();
});

app.route("/", publicRoutes);
app.route("/api", protectedRoutes);
app.route("/admin", adminRoutes);

3. RPC Mode for Type-Safe Clients

// server.ts
import { Hono } from "hono";
import { zValidator } from "@hono/zod-validator";
import { z } from "zod";

const app = new Hono()
  .get("/api/users", async (c) => {
    const users = await db.listUsers();
    return c.json(users);
  })
  .post(
    "/api/users",
    zValidator("json", z.object({ name: z.string(), email: z.string().email() })),
    async (c) => {
      const data = c.req.valid("json");
      const user = await db.createUser(data);
      return c.json(user, 201);
    }
  );

export type AppType = typeof app;

// client.ts -- full type inference without codegen
import { hc } from "hono/client";
import type { AppType } from "./server";

const client = hc<AppType>("http://localhost:3000");

// Fully typed -- autocompletion for path, input, and response
const res = await client.api.users.$post({
  json: { name: "Jane", email: "jane@example.com" },
});
const user = await res.json(); // Typed as the return type of the handler

Common Patterns

Error Handling with HTTPException

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

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);
});

// Throw in handlers or middleware
app.get("/api/users/:id", async (c) => {
  const user = await db.getUser(c.req.param("id"));
  if (!user) throw new HTTPException(404, { message: "User not found" });
  return c.json(user);
});

Cloudflare Workers with Bindings

type Bindings = {
  DB: D1Database;
  CACHE: KVNamespace;
  BUCKET: R2Bucket;
};

const app = new Hono<{ Bindings: Bindings }>();

app.get("/api/files/:key", async (c) => {
  const object = await c.env.BUCKET.get(c.req.param("key"));
  if (!object) return c.notFound();
  return new Response(object.body, {
    headers: { "Content-Type": object.httpMetadata?.contentType ?? "application/octet-stream" },
  });
});

Testing with Built-in Test Client

import { describe, it, expect } from "vitest";
import app from "./index";

describe("Users API", () => {
  it("creates a user", async () => {
    const res = await app.request("/api/users", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: "Jane", email: "jane@example.com" }),
    });
    expect(res.status).toBe(201);
    const body = await res.json();
    expect(body.name).toBe("Jane");
  });
});

Anti-Patterns

  • Importing Node.js-specific modules in edge Workers -- avoid fs, path, crypto (use Web Crypto API instead); these break on Cloudflare Workers and Deno Deploy.
  • Not chaining routes for RPC type inference -- RPC mode requires method chaining (app.get(...).post(...)) on the same Hono instance; separate app.get() calls lose the type chain.
  • Using c.req.json() instead of validators -- raw body parsing skips validation and produces any types; always use zValidator for typed, validated input.
  • Ignoring the app.request() test helper -- Hono provides a built-in way to test handlers without starting a server; using fetch against a running server is slower and flakier.

When to Use

  • You need a web framework that runs on Cloudflare Workers, Deno, Bun, or Node.js with the same codebase.
  • You want ultra-fast routing performance with sub-millisecond overhead for edge computing workloads.
  • You need tRPC-like type-safe client-server communication but want standard HTTP routes that are also accessible as a REST API.
  • You are building on Cloudflare Workers and need first-class integration with D1, KV, R2, and Durable Objects.
  • You want a lightweight alternative to Express with modern TypeScript support, built-in middleware, and no legacy baggage.

Install this skill directly: skilldb add api-gateway-services-skills

Get CLI access →

Related Skills

Kong

Configure and manage Kong API Gateway for production API infrastructure. Handle plugin configuration, rate limiting, authentication, and service routing with declarative configuration and Admin API patterns.

API Gateway Services176L

Krakend

Build with KrakenD for ultra-high performance API gateways. Use this skill when the project needs to aggregate microservices, transform API responses, apply rate limiting, or create backend-for-frontend patterns with minimal latency.

API Gateway Services178L

Nginx

Configure NGINX as a reverse proxy, load balancer, and API gateway. Manage upstream routing, SSL termination, rate limiting, caching, and security headers with production-hardened configuration patterns.

API Gateway Services204L

Traefik

Deploy and configure Traefik as a reverse proxy with automatic service discovery. Integrate Docker labels, middleware chains, Let's Encrypt TLS, and dynamic configuration for containerized microservice architectures.

API Gateway Services191L

Trpc

Build end-to-end type-safe APIs with tRPC for TypeScript full-stack applications. Define routers, procedures, and middleware with automatic type inference, Zod validation, and seamless React/Next.js client integration.

API Gateway Services236L

Apisix

Apache APISIX is a dynamic, real-time, high-performance API Gateway built on Nginx and LuaJIT, designed for managing microservices, securing APIs, and handling traffic routing. Use it to centralize API management, enforce policies, and provide a performant entry point for all your backend services.

API Gateway Services218L