All free skills / Other majors
hono 4.x
Validate requests, compose middleware and consume status-aware RPC types across packages.
- For
hono@4.13.12- Verified
- 2026-10-10, 12 examples executed
- Skill package
@modootoday/pmcp-hono@4.0.1
Use this skill for free
No PMCP login or subscription is required. Download the original instructions, or install the content-only archive with your project's package manager.
Download SKILL.md · Download package archive
npm install --save-dev https://pmcp.build/skills/hono/4/package.tgz
PMCP discovers the installed package's instructions. Connect your runtime after installation.
Archive integrity
sha512-jULntcAqbLMqWT2mMU8vpI67qAFmNxtCq9xvZZZybkTdU2xtHAzVEEoDIXR3vBN9P2Ve/MEXnOBdM9uLhxiavw==Complete instructions
The original four request examples were verified against hono@4.13.7 on 2026-09-07. Development fixtures separately verify middleware ordering, invalid JSON responses, RPC client/server type consumption and a Node HTTP request followed by server shutdown; current exact versions are recorded in the catalog.
Hono 4.x
Use the current app API
Import the recommended preset from hono, construct an app, register routes, and export or pass the app to a runtime server:
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
export default app
Hono creates a Fetch-compatible app. Its runtime/server integration is separate. For Node.js, the documented integration uses @hono/node-server and serve(app); Bun and Deno can serve Fetch handlers natively. Do not assume that importing hono starts an HTTP server.
For a standalone script, use app.request() to exercise routes without a server:
import { strict as assert } from 'node:assert'
import { Hono } from 'hono'
const app = new Hono()
app.get('/hello', (c) => c.text('Hello Hono!'))
const response = await app.request('/hello')
assert.equal(response.status, 200)
assert.equal(await response.text(), 'Hello Hono!')
app.fetch(request, env, event) is the Fetch-compatible handler API. app.request(path, options) is the convenient request helper for programmatic calls. Other documented app methods include HTTP method helpers, all, on, use, route, basePath, notFound, onError, mount, and fire.
Context and responses
Route and middleware callbacks receive a context object. The documented context surface includes c.req, c.status(), c.text(), c.json(), c.html(), c.set(), c.get(), c.var, c.header(), c.redirect(), c.notFound(), and c.body(). Cookie helpers are imported from hono/cookie.
Read request headers through c.req.header(), and set the response status with c.status() before returning a response:
import { strict as assert } from 'node:assert'
import { Hono } from 'hono'
const app = new Hono()
app.get('/created', (c) => {
const userAgent = c.req.header('User-Agent')
c.status(201)
return c.json({ userAgent })
})
const response = await app.request('/created', {
headers: { 'User-Agent': 'pmcp-example' },
})
assert.equal(response.status, 201)
assert.deepEqual(await response.json(), { userAgent: 'pmcp-example' })
Use c.json() rather than the removed c.jsonT() API.
Middleware
Create custom middleware with createMiddleware from hono/factory. Middleware receives (c, next) and must await next() when it wants downstream handlers to run:
import { strict as assert } from 'node:assert'
import { Hono } from 'hono'
import { createMiddleware } from 'hono/factory'
const app = new Hono()
const addMarker = createMiddleware(async (c, next) => {
c.set('marker', 'middleware')
await next()
})
app.use(addMarker)
app.get('/', (c) => c.text(c.get('marker')))
const response = await app.request('/')
assert.equal(await response.text(), 'middleware')
The documented built-in middleware entry points include logger from hono/logger and cors from hono/cors, used as app.use(logger()) and app.use('/api/*', cors()).
Validation
Use validator from hono/validator. Documented validation targets are form, json, query, header, cookie, and param. A validator callback may return a response for invalid input or return validated data; later handlers retrieve it with c.req.valid(target).
import { strict as assert } from 'node:assert'
import { Hono } from 'hono'
import { validator } from 'hono/validator'
const app = new Hono()
app.get(
'/search',
validator('query', (value, c) => {
const term = value['term']
if (!term || typeof term !== 'string') return c.text('Invalid!', 400)
return { term }
}),
(c) => c.json(c.req.valid('query'))
)
const valid = await app.request('/search?term=hono')
assert.equal(valid.status, 200)
assert.deepEqual(await valid.json(), { term: 'hono' })
const invalid = await app.request('/search')
assert.equal(invalid.status, 400)
assert.equal(await invalid.text(), 'Invalid!')
Hono 4 migration traps
When updating older examples, apply these changes:
c.jsonT()was removed; usec.json().c.stream()andc.streamText()moved tohono/streaming.c.env()was removed; usegetRuntimeKey().app.handleEvent()was removed; useapp.fetch().app.showRoutes()andapp.routerNamemoved toshowRoutes()andgetRouterName()fromhono/dev.c.req.cookie()was removed; usegetCookie()fromhono/cookie.app.head()is no longer needed becauseapp.get()implicitly handlesHEAD.- Hono request members including
headers(),body(),bodyUsed(),integrity(),keepalive(),referrer(), andsignal()are now accessed onreq.raw; for example,req.raw.headers. - Cloudflare Workers
serveStaticrequires a manifest, passed as{ root: './assets', manifest }. - JSX renderer
docTypenow defaults totrue. FCinhono/jsxno longer passeschildren; usePropsWithChildrenwhen children are needed.
Other entry points
The research documents these entry points:
hono/quick:Honofor applications initialized per request.hono/tiny: the smallest router package.hono/html:htmlandraw.hono/cookie:getCookieandsetCookie.hono/testing:testClient.hono/adapter:envandgetRuntimeKey.
Use the documented exports from those subpaths rather than assuming they are methods on the app or context. In particular, cookie access moved out of c.req, and runtime-key access replaced c.env().
JSX and RPC boundaries
JSX requires a .tsx file and compiler configuration with jsx: "react-jsx" and jsxImportSource: "hono/jsx"; JSX is not a plain .ts feature.
RPC is type-level and build-tool dependent. The server exports typeof route as AppType; separate projects need matching Hono versions, strict TypeScript and built declarations before consumption. Preserve project references when the existing build graph uses them. It is not something to validate with a bare bun example.ts script.
Build a typed client from the route value
Preserve the return type of the chained route registration. Export that route's type and import it with import type in the client. Keep strict TypeScript and matching Hono versions across both projects.
import { Hono } from "hono";
import { validator } from "hono/validator";
const route = new Hono().post(
"/items",
validator("json", (value: { title: string }, c) => {
if (typeof value?.title !== "string") return c.json({ error: "title" }, 400);
return { title: value.title };
}),
(c) => c.json({ title: c.req.valid("json").title }, 201),
);
export type AppType = typeof route;
export default route;
For a separate package, build exported declarations before the consumer typecheck. Use hc<AppType> from hono/client. The JSON input and status-specific response types should fail compilation when the client sends the wrong shape. Request-only tests cannot prove that boundary.
Keep serving and runtime boundaries separate
Use the runtime's documented adapter to serve app.fetch; request tests do not start a listener. Verify one valid request, one rejected request and middleware ordering before serving. Set the JSON Content-Type in validator tests. Retain the host's connection, authentication and shutdown conventions.
For Node.js, install a compatible @hono/node-server separately and close its returned server during graceful shutdown:
import { serve } from "@hono/node-server";
import app from "./app.js";
const server = serve({ fetch: app.fetch, port: 3000 });
process.once("SIGTERM", () => {
server.close();
});
The loopback fixture checks adapter 2.1.4, an assigned local port, response status and body, and listener closure. It does not validate production signal handling, WebSockets, Bun or Deno serving.
Read Hono RPC when consuming typed routes, and Node integration when starting a Node server. Other runtimes need their own documented entry point.
Remaining API coverage
Detailed signatures for the quick and tiny presets, HTML and cookie helpers, streaming, static serving and JSX components require their own task-specific examples. RPC transport authentication and non-Node server lifecycles remain outside these fixtures. Consult the relevant runtime documentation before deployment.