Hono Knowledge Patch
When to use this patch
Load this patch when writing, reviewing, debugging, or upgrading Hono applications, middleware, RPC clients, static generation, JSX, streaming, runtime adapters, or the Hono CLI.
Before changing an existing project, inspect its hono and @hono/* versions in
the package manifest and lockfile. Apply version-specific advice only when the
installed dependency contains that behavior. Prefer the project's code, types,
tests, and observed runtime behavior when they disagree with this guidance.
Read the security reference before changing authentication, caching, static-file or SSG paths, CORS, IP restrictions, cookies, SSE, body limits, or JSX/CSS SSR.
Reference index
| Reference | Topics |
|---|---|
| Routing and requests | Route introspection, mounted apps, request parsing, proxy headers, slashes, locales, Unix sockets, router correctness |
| Client, RPC, validation, and testing | hc, typed URLs and responses, serializers, validators, raw requests, test bindings |
| Security and authentication | JWT/JWK, Basic and Bearer Auth, cookies, CSP, bot blocking, CSRF, security floors |
| Middleware, runtimes, and integrations | Cache, CORS, compression, Pretty JSON, adapters, MCP, MIME, execution context, logging |
| Rendering, streaming, and SSG | Streaming lifecycle, Service Workers, SSG plugins and mapping, JSX DOM, view transitions |
| Hono CLI | Documentation lookup, in-process requests, development serving, optimized router builds |
Breaking changes, deprecations, and security floors
Configure JWT and JWK algorithms explicitly
Starting with 4.11.4, jwt requires one explicit alg, and JWK/JWKS
middleware requires an alg array containing asymmetric algorithms. Never let
an untrusted token header choose the verification algorithm.
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 4.11.10 or newer on the 4.11 line. Use 4.12.28 or newer on the 4.12
line, and never remain below 4.12.27. These floors include fixes across IP
restriction, caches, static paths, authentication, cookies, SSE, request bodies,
CORS, and JSX/CSS rendering. See the security reference for the complete
behavioral checklist.
Replace deprecated startup and SSG hooks
Start a Service Worker application with the standalone helper introduced in
4.8.0; do not add new uses of app.fire().
import { fire } from 'hono/service-worker'
fire(app)
Legacy SSG hook options are deprecated as of 4.9.0. Pass SSGPlugin objects
through toSSG(..., { plugins }). Supplying a custom plugin list disables the
implicit default plugin, so add defaultPlugin() explicitly when its normal
non-200 filtering is still required.
Treat changed wire and routing behavior as compatibility boundaries
hcpath and query values remain strings even if server validation coerces them. Path parameters are not URL-encoded; encode ordinary values yourself.- JSON and form validators receive
{}whenContent-Typedoes not match the target. Header-validator keys are lowercase. - Proxy handling follows RFC 9110 for hop-by-hop headers; do not depend on those headers passing through unchanged.
- Router fixes in
4.13.3correct suffix wildcards and prevent wildcard routes from overmatching path prefixes. Retest fallback and nested wildcard routes.
Client and RPC quick reference
Generate exact URLs and paths
Pass a literal base URL as the second hc type parameter to preserve it in the
TypedURL returned by $url().
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 the interpolated path and query string are needed.
const path = client.posts[':id'].$path({
param: { id: '42' },
query: { view: 'full' },
})
Set buildSearchParams in the hc options for nonstandard query conventions.
Per-call { init } values have final precedence and may override the method,
body, or headers generated by hc.
Parse and type responses
parseResponse() chooses a parser from Content-Type and throws a structured
DetailedError for a non-success response.
import { parseResponse } from 'hono/client'
const result = await parseResponse(client.posts.$get())
Use ApplyGlobalResponse for responses introduced by global middleware or
onError(), PickResponseByStatusCode for one status branch, and module
augmentation of NotFoundResponse for a typed custom 404. Multiple-handler
route inference includes responses from middleware and earlier handlers.
Use cloneRawRequest(c.req) when a validator or middleware has consumed the body
but an integration still needs a reconstructed raw Request.
Authentication quick reference
Choose token sources and claims deliberately
jwtacceptsheaderNamefor a custom header orcookiefor a named cookie.jwkacceptsheaderName;keysandjwks_urimay be functions of context.jwk({ allow_anon: true, ... })permits unauthenticated continuation.- JWT middleware can validate
iss;verifyOptionscontrolsnbf,iat, andexp, all enabled by default when those claims are present. - JWT and JWK middleware require the Bearer scheme when reading authorization.
- Use
JwtVariablesin the application'sVariablestype for typedc.get('jwtPayload')access.
Use Basic Auth's async-capable onAuthSuccess(c, username) hook for identity or
audit state after either direct credential checks or verifyUser succeeds.
Middleware and runtime quick reference
Keep cache and CORS variation safe
- Select stored statuses with
cacheableStatusCodes. - Handle an unavailable Cache API with
onCacheNotAvailable. - Configured
Varyheaders contribute to cache keys. - Do not cache responses with
Vary: Authorization,Vary: Cookie,private, orno-storebehavior. allowMethodsmay vary by request origin.4.13.3addsOrigintoVaryon CORS preflight responses and exemptsOPTIONSrequests from CSRF validation.
Use runtime-specific facilities
- Import
upgradeWebSocketandwebsocketdirectly fromhono/bun. - Configure binary response content types in the AWS Lambda adapter.
- Import
getConnInfofrom the AWS Lambda, Cloudflare Pages, or Netlify adapter. - Use the
http+unixURL scheme for HTTP over Unix domain sockets. - Cloudflare execution contexts expose
propsand can typeexportsthrough module augmentation. Contextis a public runtime export fromhonofor integrations needing the class rather than only its structural type.
Compression accepts contentTypeFilter; use
COMPRESSIBLE_CONTENT_TYPE_REGEX as the base for custom rules. MessagePack is
compressible. Pretty JSON accepts force: true and, with the 4.13.3 fix,
recognizes structured media types ending in +json.
Rendering, streaming, and SSG quick reference
Stop producers when a stream aborts
return streamSSE(c, async (stream) => {
while (!stream.aborted) {
await stream.writeSSE({ event: 'tick', data: 'tick' })
await stream.sleep(1000)
}
})
Use stream.onAbort() for cleanup. Errors after streaming begins go to the
helper's optional third callback, not app.onError(), because the response can
no longer be replaced. Under Wrangler, try Content-Encoding: Identity when
streaming behavior requires the workaround.
Compose static generation explicitly
import { defaultPlugin, redirectPlugin, toSSG } from 'hono/ssg'
await toSSG(app, fs, {
plugins: [redirectPlugin(), defaultPlugin()],
})
Use ssgParams() for parameterized pages, disableSSG() to omit a route,
onlySSG() for generation-only routes, and isSSGContext(c) for conditional
output. Node.js accepts a promise-based filesystem argument; Bun and Deno expose
filesystem-bound adapter entry points.
For streamed Suspense or ErrorBoundary content, set scriptNonce on
StreamingContext and allow the same nonce in CSP. jsxRenderer() may derive
options per request, and createCssContext() accepts classNameSlug.
CLI quick reference
Install @hono/cli to get 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 expressions. optimize
emits a PreparedRegExpRouter entry at dist/index.js.