bun-hono-integration — Claude Code skill: Hono APIs on Bun
A skill that tells the agent how to build Hono APIs on Bun: routes, middleware, Zod validation, RPC client. Useful when your project already runs on Bun.
npx skills add secondsky/claude-skills --skill bun-hono-integration -a claude-codeWhat bun-hono-integration does
The skill hands the agent a working reference for Hono, the lightweight web framework built for Bun. It covers routes with path parameters and wildcards, route groups via app.route() and basePath(), and request parsing for JSON, text and formData.
Middleware gets its own sections: custom handlers plus the built-ins cors, logger, basicAuth, bearerAuth, compress, etag and secureHeaders. Validation runs through zValidator with Zod schemas, context variables are typed with c.set and c.get, and errors go through HTTPException and onError. There is also RPC mode: export AppType from the server and the hc client gives you typed calls.
Quick start is bun create hono my-app, then bun install and bun run dev. Validation needs the @hono/zod-validator package alongside zod. The common-errors section in the document cuts off mid-table, so do not count on it for debugging — keep the official Hono docs within reach.
What it helps with
- stand up a REST API on Hono over Bun
- define routes with path parameters and wildcards
- wire in CORS, logging and security headers
- validate request bodies with a Zod schema
- get a typed client through RPC mode
Example prompts for the agent
- add a POST /users route with zValidator and a Zod body schema
- set up cors and logger middleware for every request
- create a typed Hono client with hc and AppType
How to install bun-hono-integration
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-hono-integration -a claude-code2Manually: put the files in place
~/.claude/skills/bun-hono-integration/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/bun-hono-integration/
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-hono-integration -a codex2Manually: put the files in place
.agents/skills/bun-hono-integration/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-hono-integration -a cursor2Manually: put the files in place
.cursor/skills/bun-hono-integration/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install secondsky/claude-skills bun-hono-integration2Manually: put the files in place
.github/skills/bun-hono-integration/SKILL.md1Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-hono-integration -a gemini-cli2Platform CLI
gemini skills install https://github.com/secondsky/claude-skills --path plugins/bun/skills/bun-hono-integrationManually: put the files in place
.devin/skills/bun-hono-integration/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add secondsky/claude-skills --skill bun-hono-integration -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about bun-hono-integration
How do I install bun-hono-integration in Claude?
Run npx skills add secondsky/claude-skills --skill bun-hono-integration -a claude-code. The skill lands at ~/.claude/skills/bun-hono-integration/SKILL.md.
What does bun-hono-integration do?
It gives the agent a Hono-on-Bun reference: routing, middleware, Zod validation, context variables, error handling and the RPC client.
What do I need for this skill to work?
A Bun project with Hono installed. Validation requires the @hono/zod-validator and zod packages.
Source text
SKILL.md · MIT
---
name: bun-hono-integration
description: Use when building APIs with Hono framework on Bun, including routing, middleware, REST APIs, context handling, or web framework features.
metadata:
version: "1.0.0"
license: MIT
---
# Bun Hono Integration
Hono is a fast, lightweight web framework optimized for Bun.
## Quick Start
```bash
bun create hono my-app
cd my-app
bun install
bun run dev
```
## Basic Setup
```typescript
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => c.text("Hello Hono!"));
app.get("/json", (c) => c.json({ message: "Hello" }));
export default app;
```
## Routing
```typescript
import { Hono } from "hono";
const app = new Hono();
// HTTP methods
app.get("/users", (c) => c.json([]));
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 }));
// 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 parameters
app.get("/posts/:postId/comments/:commentId", (c) => {
const { postId, commentId } = c.req.param();
return c.json({ postId, commentId });
});
// Wildcards
app.get("/files/*", (c) => {
const path = c.req.path;
return c.text(`File: ${path}`);
});
// Regex-like patterns
app.get("/user/:id{[0-9]+}", (c) => c.json({ id: c.req.param("id") }));
export default app;
```
## Route Groups
```typescript
import { Hono } from "hono";
const app = new Hono();
// Group routes
const api = new Hono();
api.get("/users", (c) => c.json([]));
api.get("/posts", (c) => c.json([]));
app.route("/api/v1", api);
// Basepath
const app2 = new Hono().basePath("/api/v2");
app2.get("/users", (c) => c.json([])); // /api/v2/users
export default app;
```
## Request Handling
```typescript
app.post("/submit", async (c) => {
// URL and method
console.log(c.req.url);
console.log(c.req.method);
// Headers
const auth = c.req.header("Authorization");
// Query params
const page = c.req.query("page");
const { limit, offset } = c.req.query();
// Body parsing
const json = await c.req.json();
const text = await c.req.text();
const form = await c.req.formData();
const arrayBuffer = await c.req.arrayBuffer();
// Parsed body (with validator)
const body = c.req.valid("json");
return c.json({ received: true });
});
```
## Response Types
```typescript
app.get("/responses", (c) => {
// Text
return c.text("Hello");
// JSON
return c.json({ data: "value" });
// HTML
return c.html("<h1>Hello</h1>");
// Redirect
return c.redirect("/other", 302);
// Not Found
return c.notFound();
// Custom response
return c.body("Raw body", 200, {
"Content-Type": "text/plain",
});
// Status
return c.json({ error: "Not found" }, 404);
// Headers
c.header("X-Custom", "value");
return c.json({ ok: true });
});
```
## Middleware
```typescript
import { Hono } from "hono";
const app = new Hono();
// Global middleware
app.use("*", async (c, next) => {
console.log(`${c.req.method} ${c.req.url}`);
await next();
});
// Path-specific middleware
app.use("/api/*", async (c, next) => {
const auth = c.req.header("Authorization");
if (!auth) {
return c.json({ error: "Unauthorized" }, 401);
}
await next();
});
// Multiple middleware
app.use("/admin/*", authMiddleware, adminMiddleware);
app.get("/api/data", (c) => c.json({ data: "protected" }));
export default app;
```
## Built-in Middleware
```typescript
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { basicAuth } from "hono/basic-auth";
import { bearerAuth } from "hono/bearer-auth";
import { compress } from "hono/compress";
import { etag } from "hono/etag";
import { secureHeaders } from "hono/secure-headers";
const app = new Hono();
// CORS
app.use("*", cors());
app.use("/api/*", cors({
origin: "https://example.com",
allowMethods: ["GET", "POST"],
}));
// Logger
app.use("*", logger());
// Basic Auth
app.use("/admin/*", basicAuth({
username: "admin",
password: "secret",
}));
// Bearer Token
app.use("/api/*", bearerAuth({
token: "my-token",
}));
// Compression
app.use("*", compress());
// ETag
app.use("*", etag());
// Security headers
app.use("*", secureHeaders());
export default app;
```
## Validation with Zod
```typescript
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.email(),
age: z.number().min(0).optional(),
});
app.post(
"/users",
zValidator("json", userSchema),
(c) => {
const user = c.req.valid("json");
// user is typed and validated
return c.json({ created: user });
}
);
// Query validation
const querySchema = z.object({
page: z.string().regex(/^\d+$/).optional(),
limit: z.string().regex(/^\d+$/).optional(),
});
app.get(
"/items",
zValidator("query", querySchema),
(c) => {
const { page, limit } = c.req.valid("query");
return c.json({ page, limit });
}
);
export default app;
```
## Context Variables
```typescript
import { Hono } from "hono";
type Variables = {
userId: string;
isAdmin: boolean;
};
const app = new Hono<{ Variables: Variables }>();
app.use("*", async (c, next) => {
c.set("userId", "123");
c.set("isAdmin", true);
await next();
});
app.get("/profile", (c) => {
const userId = c.get("userId");
const isAdmin = c.get("isAdmin");
return c.json({ userId, isAdmin });
});
export default app;
```
## Error Handling
```typescript
import { Hono } from "hono";
import { HTTPException } from "hono/http-exception";
const app = new Hono();
// Throw HTTP error
app.get("/error", (c) => {
throw new HTTPException(401, { message: "Unauthorized" });
});
// Global error handler
app.onError((err, c) => {
if (err instanceof HTTPException) {
return err.getResponse();
}
console.error(err);
return c.json({ error: "Internal Server Error" }, 500);
});
// Not found handler
app.notFound((c) => {
return c.json({ error: "Not Found" }, 404);
});
export default app;
```
## RPC Mode (Type-safe Client)
```typescript
// server.ts
import { Hono } from "hono";
import { hc } from "hono/client";
const app = new Hono()
.get("/users", (c) => c.json([{ id: 1, name: "Alice" }]))
.post("/users", async (c) => {
const body = await c.req.json();
return c.json({ created: body });
});
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 calls
const res = await client.users.$get();
const users = await res.json(); // Typed!
const created = await client.users.$post({
json: { name: "Bob" },
});
```
## Common Errors
| Error | Cause | Fix |
|-------|-------|-----|
| `Route not found` | Wrong path | Check route registration |
| `Body already read` | Double parsing | Read body once |
| `Validator error` | Invalid input | Check schema definition |
| `Middleware order` | Wrong execution | Register middleware first |
## When to Load References
Load `references/middleware-list.md` when:
- Complete middleware reference
- Custom middleware patterns
Load `references/openapi.md` when:
- OpenAPI/Swagger integration
- API documentation generation
© secondsky · MIT · secondsky/claude-skills