Skip to content
hono logo

Hono

hono

Builds APIs with Hono including routing, middleware, validation, and edge deployment. Use when creating fast APIs, building edge functions, or developing serverless applications.

SKILL.md

Full skill instructions

Hono

Ultrafast web framework for the edge, built on Web Standards.

Quick Start

Install:

npm install hono

Create project:

npm create hono@latest my-app

Basic Server

// src/​index.ts
import { Hono } from 'hono';

const app = new Hono();

app.get('/', (c) => {
  return c.text('Hello Hono!');
});

app.get('/​json', (c) => {
  return c.json({ message: 'Hello' });
});

export default app;

Routing

Basic Routes

import { Hono } from 'hono';

const app = new Hono();

// HTTP methods
app.get('/​users', (c) => c.json({ users: [] }));
app.post('/​users', (c) => c.json({ created: true }));
app.put('/​users/:id', (c) => c.json({ updated: true }));
app.delete('/​users/:id', (c) => c.json({ deleted: true }));
app.patch('/​users/:id', (c) => c.json({ patched: true }));

// All methods
app.all('/​any', (c) => c.text('Any method'));

Path Parameters

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

// Multiple params
app.get('/​posts/:postId/​comments/:commentId', (c) => {
  const { postId, commentId } = c.req.param();
  return c.json({ postId, commentId });
});

// Optional params
app.get('/​posts/:id?', (c) => {
  const id = c.req.param('id');
  return c.json({ id: id || 'all' });
});

// Wildcard
app.get('/​files/​*', (c) => {
  const path = c.req.path;
  return c.text(`File: ${path}`);
});

Query Parameters

app.get('/​search', (c) => {
  const query = c.req.query('q');
  const page = c.req.query('page') || '1';

  // Multiple values
  const tags = c.req.queries('tags');

  return c.json({ query, page, tags });
});

Route Groups

const app = new Hono();

// Group routes
const api = new Hono();
api.get('/​users', (c) => c.json({ users: [] }));
api.get('/​posts', (c) => c.json({ posts: [] }));

app.route('/​api/​v1', api);

// Chaining
app.basePath('/​api').get('/​users', (c) => c.json([]));

Request Handling

Request Body

// JSON body
app.post('/​users', async (c) => {
  const body = await c.req.json();
  return c.json(body);
});

// Form data
app.post('/​upload', async (c) => {
  const formData = await c.req.formData();
  const name = formData.get('name');
  return c.text(`Name: ${name}`);
});

// Text body
app.post('/​text', async (c) => {
  const text = await c.req.text();
  return c.text(text);
});

// Array buffer
app.post('/​binary', async (c) => {
  const buffer = await c.req.arrayBuffer();
  return c.text(`Size: ${buffer.byteLength}`);
});

Headers

app.get('/​headers', (c) => {
  const auth = c.req.header('Authorization');
  const contentType = c.req.header('Content-Type');

  return c.json({ auth, contentType });
});

Response

Response Types

// Text
app.get('/​text', (c) => c.text('Hello'));

// JSON
app.get('/​json', (c) => c.json({ message: 'Hello' }));

// HTML
app.get('/​html', (c) => c.html('<h1>Hello</​h1>'));

// Redirect
app.get('/​redirect', (c) => c.redirect('/​new-path'));

// Custom status
app.get('/​error', (c) => {
  return c.json({ error: 'Not found' }, 404);
});

// With headers
app.get('/​custom', (c) => {
  return c.json(
    { data: 'value' },
    200,
    { 'X-Custom-Header': 'value' }
  );
});

Streaming

import { streamText } from 'hono/​streaming';

app.get('/​stream', (c) => {
  return streamText(c, async (stream) => {
    for (let i = 0; i < 5; i++) {
      await stream.write(`data: ${i}\n`);
      await stream.sleep(1000);
    }
  });
});

Middleware

Built-in Middleware

import { Hono } from 'hono';
import { cors } from 'hono/​cors';
import { logger } from 'hono/​logger';
import { prettyJSON } from 'hono/​pretty-json';
import { secureHeaders } from 'hono/​secure-headers';
import { compress } from 'hono/​compress';
import { etag } from 'hono/​etag';

const app = new Hono();

app.use('*', logger());
app.use('*', cors());
app.use('*', prettyJSON());
app.use('*', secureHeaders());
app.use('*', compress());
app.use('*', etag());

Custom Middleware

import { Hono, Context, Next } from 'hono';

// Simple middleware
const timing = async (c: Context, next: Next) => {
  const start = Date.now();
  await next();
  const ms = Date.now() - start;
  c.header('X-Response-Time', `${ms}ms`);
};

app.use('*', timing);

// Middleware with options
const auth = (secret: string) => {
  return async (c: Context, next: Next) => {
    const token = c.req.header('Authorization');

    if (token !== `Bearer ${secret}`) {
      return c.json({ error: 'Unauthorized' }, 401);
    }

    await next();
  };
};

app.use('/​api/​*', auth('my-secret'));

Route-specific Middleware

app.get('/​protected', auth('secret'), (c) => {
  return c.json({ protected: true });
});

// Multiple middleware
app.post('/​data', logger(), auth('secret'), validate(), (c) => {
  return c.json({ success: true });
});

Validation

Zod Validator

npm install @hono/​zod-validator
import { Hono } from 'hono';
import { zValidator } from '@hono/​zod-validator';
import { z } from 'zod';

const app = new Hono();

const userSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
  age: z.number().min(0).optional(),
});

app.post(
  '/​users',
  zValidator('json', userSchema),
  (c) => {
    const user = c.req.valid('json');
    return c.json({ user });
  }
);

// Query validation
const querySchema = z.object({
  page: z.string().transform(Number).default('1'),
  limit: z.string().transform(Number).default('10'),
});

app.get(
  '/​users',
  zValidator('query', querySchema),
  (c) => {
    const { page, limit } = c.req.valid('query');
    return c.json({ page, limit });
  }
);

// Param validation
const paramSchema = z.object({
  id: z.string().uuid(),
});

app.get(
  '/​users/:id',
  zValidator('param', paramSchema),
  (c) => {
    const { id } = c.req.valid('param');
    return c.json({ id });
  }
);

Context Variables

import { Hono } from 'hono';

type Variables = {
  user: { id: string; name: string };
};

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

// Set variable in middleware
app.use('*', async (c, next) => {
  c.set('user', { id: '123', name: 'John' });
  await next();
});

// Access in handler
app.get('/​me', (c) => {
  const user = c.get('user');
  return c.json(user);
});

Error Handling

import { Hono, HTTPException } from 'hono';

const app = new Hono();

// Throw HTTP exception
app.get('/​error', (c) => {
  throw new HTTPException(404, { message: 'Not found' });
});

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

// Not found handler
app.notFound((c) => {
  return c.json({ error: 'Not Found' }, 404);
});

RPC Mode

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

const app = new Hono()
  .get('/​users', (c) => {
    return c.json([{ id: 1, name: 'John' }]);
  })
  .post(
    '/​users',
    zValidator('json', z.object({ name: z.string() })),
    (c) => {
      const { name } = c.req.valid('json');
      return c.json({ id: 2, name });
    }
  );

export type AppType = typeof app;
export default app;

// client.ts
import { hc } from 'hono/​client';
import type { AppType } from './​server';

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

// Type-safe client calls
const users = await client.users.$get();
const data = await users.json();

const newUser = await client.users.$post({
  json: { name: 'Jane' },
});

Deployment

Cloudflare Workers

// src/​index.ts
import { Hono } from 'hono';

type Bindings = {
  KV: KVNamespace;
  DB: D1Database;
};

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

app.get('/​kv/:key', async (c) => {
  const key = c.req.param('key');
  const value = await c.env.KV.get(key);
  return c.json({ value });
});

export default app;

Vercel

// api/​index.ts
import { Hono } from 'hono';
import { handle } from 'hono/​vercel';

const app = new Hono().basePath('/​api');

app.get('/​hello', (c) => c.json({ message: 'Hello from Vercel' }));

export const GET = handle(app);
export const POST = handle(app);

Node.js

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

const app = new Hono();

app.get('/', (c) => c.text('Hello Node.js!'));

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

Bun

import { Hono } from 'hono';

const app = new Hono();

app.get('/', (c) => c.text('Hello Bun!'));

export default {
  port: 3000,
  fetch: app.fetch,
};

JSX

import { Hono } from 'hono';
import { html } from 'hono/​html';

const app = new Hono();

const Layout = ({ children }: { children: any }) => html`
  <!DOCTYPE html>
  <html>
    <head>
      <title>My App</​title>
    </​head>
    <body>
      ${children}
    </​body>
  </​html>
`;

app.get('/', (c) => {
  return c.html(
    <Layout>
      <h1>Hello, World!</​h1>
    </​Layout>
  );
});

Best Practices

  1. Use validators - Validate all inputs
  2. Type your bindings - For edge environments
  3. Handle errors globally - Use onError
  4. Use middleware - Reusable logic
  5. Export types for RPC - Type-safe clients

Common Mistakes

MistakeFix
Forgetting asyncUse async/​await for body
Wrong content typeUse c.json(), c.text() etc.
Missing error handlingAdd onError handler
Not validatingUse zValidator
Blocking event loopKeep handlers fast

Reference Files

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View