Hono Knowledge Patch
Use this skill when writing, reviewing, upgrading, or debugging Hono applications, middleware, clients, tests, rendering, static generation, or command-line workflows.
Working rules
- Read the security reference before changing authentication, caching, CORS, IP restrictions, cookies, static files, SSG paths, JSX/CSS SSR, or streaming.
- Read the relevant topic reference before relying on client inference, adapter exports, route metadata, validator input, or generated-file behavior.
- Keep client
paramandqueryvalues in their wire-format string form, even when server-side validators coerce them. - Preserve explicit JWT/JWK algorithms and the applicable security patch floor.
- Choose adapter and SSG entry points for the actual runtime.
- Prefer project manifests, code, and tests when they demonstrate newer behavior.
Reference index
| Reference | Topics |
|---|---|
| Routing and requests | Route introspection, mounted paths, request bodies, proxies, trailing slashes, locales, sockets, and router fixes |
| Client, RPC, validation, and testing | hc, response types and parsing, URL generation, validators, Standard Schema, testClient, and app.request() |
| Security and authentication | JWT/JWK, Basic and Bearer Auth, cookies, CSP, bot blocking, CSRF, and security floors |
| Middleware, runtimes, and integrations | Cache, CORS, compression, adapters, Service Workers, MCP, MIME, logging, context, ETag, and Pretty JSON |
| Rendering, streaming, and SSG | Stream lifecycle, static generation, JSX DOM, view transitions, renderers, and CSS |
| Hono CLI | Documentation lookup, in-process requests, local serving, and optimized router builds |
Breaking changes, deprecations, and security floors
Configure JWT and JWK algorithms explicitly
From v4.11.4, jwt requires one explicit alg; jwk requires an alg array
of asymmetric algorithms. Never allow a token header to select verification.
import { jwk } from 'hono/jwk'
import { jwt } from 'hono/jwt'
app.use('/session/*', jwt({ secret, alg: 'HS256' }))
app.use('/admin/*', jwk({ jwks_uri, alg: ['RS256'] }))
Use v4.11.10 or newer on the 4.11 line. On the 4.12 line, use v4.12.28 or newer and never remain below v4.12.27. These floors include fixes for auth, cache variation, IP restrictions, static and SSG paths, cookies, SSE, body limits, CORS credentials, JSX/CSS SSR, and timing-safe comparison.
Replace deprecated startup and SSG hooks
Start a Service Worker with the standalone helper; do not add app.fire().
import { fire } from 'hono/service-worker'
fire(app)
Supply SSGPlugin objects through toSSG(..., { plugins }). Legacy SSG hook
options are deprecated. Supplying custom plugins removes the implicit default,
so include defaultPlugin() when its normal filtering is still required.
Account for changed request and router behavior
- Middleware responses now participate in multi-handler RPC response unions.
- Proxying processes hop-by-hop headers according to RFC 9110; do not rely on those headers passing through unchanged.
- JSON and form validators receive
{}without their matchingContent-Type, and header-validator keys are lowercase. hcinterpolates path parameters without URL-encoding. Encode ordinary values explicitly; pass raw slashes only to a route designed for them.- From 4.13.3, wildcard matching respects route boundaries, suffix wildcards match correctly, and dollar-token text remains literal in client paths.
Client and RPC quick reference
Build paths and typed URLs
Pass a literal base URL as the second hc type parameter when $url() should
retain an exact TypedURL type.
const client = hc<typeof app, 'https://api.example.com'>(
'https://api.example.com/'
)
const url = client.posts[':id'].$url({ param: { id: '42' } })
Use $path() when only a path and query string are needed.
const path = client.posts[':id'].$path({
param: { id: '42' },
query: { view: 'full' },
})
Customize query conventions with buildSearchParams. Per-call { init } has
final precedence over the method, body, and headers generated by hc.
Type and parse responses
Use ApplyGlobalResponse to add global-middleware or onError() responses to
every route schema. Use PickResponseByStatusCode to select one status variant,
and augment NotFoundResponse when a custom 404 body must remain typed.
parseResponse() chooses a parser from Content-Type and throws
DetailedError for an unsuccessful response.
import { parseResponse } from 'hono/client'
const result = await parseResponse(client.posts.$get())
Use cloneRawRequest(c.req) after a validator or middleware has consumed the
body but another integration still needs a raw Request.
Authentication quick reference
Choose token sources deliberately
jwtacceptsheaderNamefor a nonstandard header andcookiefor a named cookie.jwkacceptsheaderName;keysandjwks_urimay be context-dependent functions.jwk({ allow_anon: true, ... })permits anonymous continuation when no valid token is available.- Current JWT/JWK behavior requires the
Bearerauthorization scheme. - Use
JwtVariablessoc.get('jwtPayload')retains its inferred type.
Configure issuer and temporal-claim verification in middleware. Use Basic
Auth's async-capable onAuthSuccess(c, username) for identity state or audit
work after either credential or verifyUser authentication succeeds.
Protect streamed JSX
Wrap streamed Suspense or ErrorBoundary content in a StreamingContext
whose scriptNonce is also allowed by the response CSP. CSP configuration can
also include report-to and report-uri reporting directives.
Middleware and runtime quick reference
Configure cache variation and availability
- Select stored statuses with
cacheableStatusCodes. - Handle a missing runtime Cache API with
onCacheNotAvailable. - Configured
Varyheaders contribute to cache keys. - Do not cache responses marked
privateorno-store, or responses varying onAuthorizationorCookie.
Use an origin callback for dynamic CORS allowMethods. Compression accepts
contentTypeFilter; start custom logic from
COMPRESSIBLE_CONTENT_TYPE_REGEX. MessagePack is compressible.
Use runtime-specific exports
- Import
upgradeWebSocketandwebsocketdirectly fromhono/bun. - Import
getConnInfofrom the AWS Lambda, Cloudflare Pages, or Netlify adapter. - Configure AWS Lambda binary content types for binary responses.
- Use
http+unixURLs for HTTP over Unix domain sockets. - Module-augment
ExecutionContext.exportsfor generated Cloudflare export types; runtime-providedpropsis also part ofExecutionContext.
Rendering, streaming, and SSG quick reference
Stop producers on abort and handle late errors
Long-lived producers should stop when stream.aborted becomes true and may use
stream.onAbort() for cleanup. Errors after the response starts go to the
stream helper's third callback, not app.onError(); that callback can finish
the existing stream but cannot replace its response.
Under Wrangler, set Content-Encoding: Identity when needed to work around
streaming behavior.
Compose static generation
import { defaultPlugin, redirectPlugin, toSSG } from 'hono/ssg'
await toSSG(app, fs, {
plugins: [redirectPlugin(), defaultPlugin()],
})
Use ssgParams() to enumerate dynamic pages, disableSSG() to exclude routes,
onlySSG() for generation-only routes, and isSSGContext(c) for conditional
generation output. Node.js accepts a filesystem argument; Bun and Deno expose
filesystem-bound entry points.
Use function-based jsxRenderer() options for request-dependent configuration
and createCssContext({ classNameSlug }) for project-specific CSS slugs.
CLI quick reference
Install @hono/cli for the hono command.
hono search "basic auth"
hono docs /docs/middleware/builtin/basic-auth
hono request -P /api/users -X POST -d '{"name":"Ada"}' src/index.ts
hono serve --use 'logger()' src/index.ts
hono optimize src/index.ts
request invokes app.request() in-process. serve defaults to
http://localhost:7070 and accepts repeated --use middleware. optimize
emits a precomputed PreparedRegExpRouter entry at dist/index.js.