NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
npm · #1282 most downloaded on npm
Web framework built on Web Standards
Last release 4 days ago
24 Sep 2026
Ships on a steady schedule
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
5 years old
451 releases · first in 2021
One column per quarter.
chore: add a monochrome logo image by @yusukebe in https://github.com/honojs/hono/pull/4487
Full Changelog: https://github.com/honojs/hono/compare/v4.10.3...v4.10.4
A security issue in the CORS middleware has been fixed. In some cases, a request header could affect the Vary response header. Please update to the la
A security issue in the CORS middleware has been fixed. In some cases, a request header could affect the Vary response header. Please update to the latest version if you are using the CORS middleware.
= by @ryuapp in https://github.com/honojs/hono/pull/4478Full Changelog: https://github.com/honojs/hono/compare/v4.10.2...v4.10.3
This change is classified as a security hardening improvement, but the lack of validation can still be considered a vulnerability in deployments that…
If you are using JWT middleware, please read the following and consider applying the configuration.
Hono’s JWT authentication middleware did not validate the aud (Audience) claim by default. As a result, applications using the middleware without an explicit audience check could accept tokens intended for other audiences, leading to potential cross-service access (token mix-up).
The issue is addressed by adding a new verification.aud configuration option to allow RFC 7519–compliant audience validation. This change is classified as a security hardening improvement, but the lack of validation can still be considered a vulnerability in deployments that rely on default JWT verification.
You can enable RFC 7519–compliant audience validation using the new verification.aud option:
import { Hono } from 'hono'
import { jwt } from 'hono/jwt'
const app = new Hono()
app.use(
'/api/*',
jwt({
secret: 'my-secret',
verification: {
// Require this API to only accept tokens with aud = 'service-a'
aud: 'service-a',
},
})
)
Full Changelog: https://github.com/honojs/hono/compare/v4.10.1...v4.10.2
fix(types): cannot .use non-return mw from createMiddleware by @NamesMT in https://github.com/honojs/hono/pull/4465
.use non-return mw from createMiddleware by @NamesMT in https://github.com/honojs/hono/pull/4465Full Changelog: https://github.com/honojs/hono/compare/v4.10.0...v4.10.1
This release brings improved TypeScript support and new utilities.
Hono v4.10.0 is now available!
This release brings improved TypeScript support and new utilities.
The main highlight is the enhanced middleware type definitions that solve a long-standing issue with type safety for RPC clients.
Imagine the following app:
import { Hono } from 'hono'
const app = new Hono()
const routes = app.get(
'/',
(c) => {
return c.json({ errorMessage: 'Error!' }, 500)
},
(c) => {
return c.json({ message: 'Success!' }, 200)
}
)
The client with RPC:
import { hc } from 'hono/client'
const client = hc<typeof routes>('/')
const res = await client.index.$get()
if (res.status === 500) {
}
if (res.status === 200) {
}
Previously, it couldn't infer the responses from middleware, so a type error was thrown.
<img width="1538" height="724" alt="CleanShot 2025-10-17 at 06 51 48@2x" src="https://github.com/user-attachments/assets/7e660db0-6c52-4249-9a3d-2932614bbace" />
Now the responses are correctly typed.
<img width="1586" height="876" alt="CleanShot 2025-10-17 at 06 54 13@2x" src="https://github.com/user-attachments/assets/ef6136f1-bc26-4625-9238-0aec25110efc" />
This was a long-standing issue and we were thinking it was super difficult to resolve it. But now come true.
Thank you for the great work @slawekkolodziej!
The new cloneRawRequest utility allows you to clone the raw Request object after it has been consumed by validators or middleware.
import { cloneRawRequest } from 'hono/request'
app.post('/api', async (c) => {
const body = await c.req.json()
// Clone the consumed request
const clonedRequest = cloneRawRequest(c.req)
await externalLibrary.process(clonedRequest)
})
Thanks @kamaal111!
Full Changelog: https://github.com/honojs/hono/compare/v4.9.12...v4.10.0
refactor: internal structure of PreparedRegExpRouter for optimization and added tests by @usualoma in https://github.com/honojs/hono/pull/4456
PreparedRegExpRouter for optimization and added tests by @usualoma in https://github.com/honojs/hono/pull/4456tree shaking by @usualoma in https://github.com/honojs/hono/pull/4458Full Changelog: https://github.com/honojs/hono/compare/v4.9.11...v4.9.12
fix(types): fix 4.9.8 regression by @aadito123 in https://github.com/honojs/hono/pull/4448
Full Changelog: https://github.com/honojs/hono/compare/v4.9.10...v4.9.11
fix(context): Fix #4427 type regression by removing non-public export by @aantthony in https://github.com/honojs/hono/pull/4433
Full Changelog: https://github.com/honojs/hono/compare/v4.9.9...v4.9.10
fix(service-worker): Update service-worker fire() to accept generic variants of Hono app instance by @harmony7 in https://github.com/honojs/hono/pull/
handle by @yusukebe in https://github.com/honojs/hono/pull/4421Full Changelog: https://github.com/honojs/hono/compare/v4.9.8...v4.9.9
fix(types): JSONParsed infer unknown values by @BarryThePenguin in https://github.com/honojs/hono/pull/4405
Full Changelog: https://github.com/honojs/hono/compare/v4.9.7...v4.9.8
Fixed an issue in the bodyLimit middleware where the body size limit could be bypassed when both Content-Length and Transfer-Encoding headers were pre
bodyLimit middleware where the body size limit could be bypassed when both Content-Length and Transfer-Encoding headers were present. If you are using this middleware, please update immediately. Security AdvisoryparseResponse not parsing json in react native by @lr0pb in https://github.com/honojs/hono/pull/4399.tool-versions file by @3w36zj6 in https://github.com/honojs/hono/pull/4397bun install commands to use --frozen-lockfile by @3w36zj6 in https://github.com/honojs/hono/pull/4398Full Changelog: https://github.com/honojs/hono/compare/v4.9.6...v4.9.7
Fixed a bug in URL path parsing (getPath) that could cause path confusion under malformed requests.
Fixed a bug in URL path parsing (getPath) that could cause path confusion under malformed requests.
If you rely on reverse proxies (e.g. Nginx) for ACLs or restrict access to endpoints like /admin, please update immediately.
See advisory for details: GHSA-9hp6-4448-45g2
Full Changelog: https://github.com/honojs/hono/compare/v4.9.5...v4.9.6
chore: replace supertest with undici by @BarryThePenguin in https://github.com/honojs/hono/pull/4365
origin and allowMethods by @jobrk in https://github.com/honojs/hono/pull/4373app.fetch in handle by @yusukebe in https://github.com/honojs/hono/pull/4374Full Changelog: https://github.com/honojs/hono/compare/v4.9.4...v4.9.5
chore: add a type cast to run deno publish by @yusukebe in https://github.com/honojs/hono/pull/4364
deno publish by @yusukebe in https://github.com/honojs/hono/pull/4364Full Changelog: https://github.com/honojs/hono/compare/v4.9.3...v4.9.4
feat(csrf): Add modern CSRF protection with Fetch Metadata support by @meck93 in https://github.com/honojs/hono/pull/4353
customFetch option to allow custom fetch function by @yusukebe in https://github.com/honojs/hono/pull/4360typescript to 5.9.2 by @yusukebe in https://github.com/honojs/hono/pull/4362packageManager field to package.json by @yusukebe in https://github.com/honojs/hono/pull/4363Full Changelog: https://github.com/honojs/hono/compare/v4.9.2...v4.9.3
fix(jsx): 'plaintext-only' value for contenteditable attribute by @object1037 in https://github.com/honojs/hono/pull/4349
removeIndexString by @yusukebe in https://github.com/honojs/hono/pull/4352Full Changelog: https://github.com/honojs/hono/compare/v4.9.1...v4.9.2
feat(parseResponse): set DetailedError.name (+ error tests) by @NamesMT in https://github.com/honojs/hono/pull/4344
DetailedError.name (+ error tests) by @NamesMT in https://github.com/honojs/hono/pull/4344Full Changelog: https://github.com/honojs/hono/compare/v4.9.0...v4.9.1
feat(ssg): mark old hook options as deprecated https://github.com/honojs/hono/pull/4331
Hono v4.9.0 is now available!
This release introduces several enhancements and utilities.
The main highlight is the new parseResponse utility that makes it easier to work with RPC client responses.
The new parseResponse utility provides a convenient way to parse responses from Hono RPC clients (hc). It automatically handles different response formats and throws structured errors for failed requests.
import { parseResponse, DetailedError } from 'hono/client'
// result contains the parsed response body (automatically parsed based on Content-Type)
const result = await parseResponse(client.hello.$get()).catch(
// parseResponse automatically throws an error if response is not ok
(e: DetailedError) => {
console.error(e)
}
)
This makes working with RPC client responses much more straightforward and type-safe.
Thanks @NamesMT!
iss) claim by @yolocat-dev in https://github.com/honojs/hono/pull/4253headerName to JWK middleware by @JoaquinGimenez1 in https://github.com/honojs/hono/pull/4279join to correct path resolution by @yusukebe in https://github.com/honojs/hono/pull/4291verifyWithJwks for external use by @Beyondo in https://github.com/honojs/hono/pull/4302parseResponse util to smartly parse hc's Response by @NamesMT in https://github.com/honojs/hono/pull/4314skipLibCheck to resolve TypeScript compilation issues by @yusukebe in https://github.com/honojs/hono/pull/4342Full Changelog: https://github.com/honojs/hono/compare/v4.8.12...v4.9.0
fix(router): support /files/:name{.*} by @yusukebe in https://github.com/honojs/hono/pull/4329
/files/:name{.*} by @yusukebe in https://github.com/honojs/hono/pull/4329Full Changelog: https://github.com/honojs/hono/compare/v4.8.11...v4.8.12
fix(types): should populate output type for c.body() by @NamesMT in https://github.com/honojs/hono/pull/4318
output type for c.body() by @NamesMT in https://github.com/honojs/hono/pull/4318FetchEvent as second argument to app.fetch by @yusukebe in https://github.com/honojs/hono/pull/4328@hono/eslint-config by @yusukebe in https://github.com/honojs/hono/pull/4330Full Changelog: https://github.com/honojs/hono/compare/v4.8.10...v4.8.11
chore: add EditorConfig by @3w36zj6 in https://github.com/honojs/hono/pull/4309
benchmarks/* by @yusukebe in https://github.com/honojs/hono/pull/4317Full Changelog: https://github.com/honojs/hono/compare/v4.8.9...v4.8.10
fix(context): use isByteString in c.redirect by @yusukebe in https://github.com/honojs/hono/pull/4307
isByteString in c.redirect by @yusukebe in https://github.com/honojs/hono/pull/4307Full Changelog: https://github.com/honojs/hono/compare/v4.8.8...v4.8.9
docs: simplify the readme by @yusukebe in https://github.com/honojs/hono/pull/4305
safeEncodeURI by @yusukebe in https://github.com/honojs/hono/pull/4306Full Changelog: https://github.com/honojs/hono/compare/v4.8.7...v4.8.8
chore: fix the deno version for publishing to jsr by @yusukebe in https://github.com/honojs/hono/pull/4304
Full Changelog: https://github.com/honojs/hono/compare/v4.8.6...v4.8.7
perf(types): remove unnecessary default types by @yusukebe in https://github.com/honojs/hono/pull/4282
Full Changelog: https://github.com/honojs/hono/compare/v4.8.5...v4.8.6
fix(serve-static): support Windows by @yusukebe in https://github.com/honojs/hono/pull/3477
Full Changelog: https://github.com/honojs/hono/compare/v4.8.4...v4.8.5
test: correct usages of Proxy to support Node.js 24 by @yusukebe in https://github.com/honojs/hono/pull/4260
Proxy to support Node.js 24 by @yusukebe in https://github.com/honojs/hono/pull/4260signingSecret option by @yusukebe in https://github.com/honojs/hono/pull/4263index string when calling $url() by @yusukebe in https://github.com/honojs/hono/pull/4267req.json() keeps the content as is by @yusukebe in https://github.com/honojs/hono/pull/4269Full Changelog: https://github.com/honojs/hono/compare/v4.8.3...v4.8.4
fix(cookie): use tryDecode when parsing cookie by @yusukebe in https://github.com/honojs/hono/pull/4240
tryDecode when parsing cookie by @yusukebe in https://github.com/honojs/hono/pull/4240JwtTokenIssuedAt error message by @yusukebe in https://github.com/honojs/hono/pull/4244pkg.pr.new by @NEKOYASAN in https://github.com/honojs/hono/pull/4245Full Changelog: https://github.com/honojs/hono/compare/v4.8.2...v4.8.3
fix(utils/color): avoid resolving pacakages via Bun.build by @ryuapp in https://github.com/honojs/hono/pull/4239
Full Changelog: https://github.com/honojs/hono/compare/v4.8.1...v4.8.2
docs(bearer-auth): fix typo by @Einherjar1632 in https://github.com/honojs/hono/pull/4238
Full Changelog: https://github.com/honojs/hono/compare/v4.8.0...v4.8.1
The app.fire() method is now deprecated in favor of this approach. Goodbye app.fire().
Hono v4.8.0 is now available!
This release enhances existing features with new options and introduces powerful helpers for routing and static site generation. Additionally, we're introducing new third-party middleware packages.
fire() FunctionPlus new third-party middleware:
Let's look at each of these.
First, this update reduces the code size! The smallest hono/tiny package has been reduced by about 800 bytes from v4.7.11, bringing it down to approximately 11 KB. When gzipped, it's only 4.5 KB. Very tiny!
New route helper functions provide easy access to route information and path utilities.
import { Hono } from 'hono'
import {
matchedRoutes,
routePath,
baseRoutePath,
basePath,
} from 'hono/route'
const api = new Hono()
api.get('/users/:id/posts/:postId', (c) => {
const matched = matchedRoutes(c) // Array of matched route handlers
const current = routePath(c) // '/api/users/:id/posts/:postId'
const base = baseRoutePath(c) // '/api' Base route path
const appBase = basePath(c) // '/api' Base path
return c.json({ matched, current, base, appBase })
})
const app = new Hono()
app.route('/api', api)
export default app
These helpers make route introspection cleaner and more explicit.
Thanks @usualoma!
JWT middleware now supports custom header locations beyond the standard Authorization header. You can specify any header name to retrieve JWT tokens from.
import { Hono } from 'hono'
import { jwt } from 'hono/jwt'
const app = new Hono()
app.use(
'/api/*',
jwt({
secret: 'secret-key',
headerName: 'X-Auth-Token', // Custom header name
})
)
app.get('/api/protected', (c) => {
return c.json({ message: 'Protected resource' })
})
This is useful when working with APIs that use non-standard authentication headers.
Thanks @kunalbhagawati!
JSX streaming now supports nonce values for Content Security Policy (CSP) compliance. The streaming context can include a nonce that gets applied to inline scripts.
import { Hono } from 'hono'
import {
renderToReadableStream,
Suspense,
StreamingContext,
} from 'hono/jsx/streaming'
const app = new Hono()
app.get('/', (c) => {
const stream = renderToReadableStream(
<html>
<body>
<StreamingContext
value={{ scriptNonce: 'random-nonce-value' }}
>
<Suspense fallback={<div>Loading...</div>}>
<AsyncComponent />
</Suspense>
</StreamingContext>
</body>
</html>
)
return c.body(stream, {
headers: {
'Content-Type': 'text/html; charset=UTF-8',
'Transfer-Encoding': 'chunked',
'Content-Security-Policy':
"script-src 'nonce-random-nonce-value'",
},
})
})
Thanks @usualoma!
CORS middleware now supports dynamic allowedMethods based on the request origin. You can provide a function that returns different allowed methods depending on the origin.
import { Hono } from 'hono'
import { cors } from 'hono/cors'
const app = new Hono()
app.use(
'*',
cors({
origin: ['https://example.com', 'https://api.example.com'],
allowMethods: (origin) => {
if (origin === 'https://api.example.com') {
return ['GET', 'POST', 'PUT', 'DELETE']
}
return ['GET', 'POST'] // Default for other origins
},
})
)
This enables fine-grained control over CORS policies per origin.
Thanks @Kanahiro!
JWK middleware now supports anonymous access with the allow_anon option. When enabled, requests without valid tokens can still proceed to your handlers.
import { Hono } from 'hono'
import { jwk } from 'hono/jwk'
const app = new Hono()
app.use(
'/api/*',
jwk({
jwks_uri: 'https://example.com/.well-known/jwks.json',
allow_anon: true,
})
)
app.get('/api/data', (c) => {
const payload = c.get('jwtPayload')
if (payload) {
return c.json({ message: 'Authenticated user', user: payload })
}
return c.json({ message: 'Anonymous access' })
})
Additionally, keys and jwks_uri options now support functions that receive the context, enabling dynamic key resolution.
Thanks @Beyondo!
Cache middleware now allows you to specify which status codes should be cached using the cacheableStatusCodes option.
import { Hono } from 'hono'
import { cache } from 'hono/cache'
const app = new Hono()
app.use(
'*',
cache({
cacheName: 'my-cache',
cacheControl: 'max-age=3600',
cacheableStatusCodes: [200, 404], // Cache both success and not found responses
})
)
Thanks @miyamo2!
A new fire() function is available from the Service Worker adapter, providing a cleaner alternative to app.fire().
import { Hono } from 'hono'
import { fire } from 'hono/service-worker'
const app = new Hono()
app.get('/', (c) => c.text('Hello from Service Worker!'))
// Use the standalone fire function
fire(app)
The app.fire() method is now deprecated in favor of this approach. Goodbye app.fire().
Static Site Generation (SSG) now supports a plugin system that allows you to extend the generation process with custom functionality.
For example, the following is easy implementation of a sitemap plugin:
// plugins.ts
import fs from 'node:fs/promises'
import path from 'node:path'
import type { SSGPlugin } from 'hono/ssg'
import { DEFAULT_OUTPUT_DIR } from 'hono/ssg'
export const sitemapPlugin = (baseURL: string): SSGPlugin => {
return {
afterGenerateHook: (result, fsModule, options) => {
const outputDir = options?.dir ?? DEFAULT_OUTPUT_DIR
const filePath = path.join(outputDir, 'sitemap.xml')
const urls = result.files.map((file) =>
new URL(file, baseURL).toString()
)
const siteMapText = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.map((url) => `<url><loc>${url}</loc></url>`).join('\n')}
</urlset>`
fsModule.writeFile(filePath, siteMapText)
},
}
}
Applying the plugin:
import { toSSG } from 'hono/ssg'
import { sitemapPlugin } from './plugins'
toSSG(app, fs, {
plugins: [sitemapPlugin('https://example.com')],
})
Plugins can hook into various stages of the generation process to perform custom actions.
Thanks @3w36zj6!
In addition to core Hono features, we're excited to introduce new third-party middleware packages that extend Hono's capabilities.
A new middleware package @hono/mcp enables creating remote MCP (Model Context Protocol) servers over Streamable HTTP Transport. This is the initial release with more features planned for the future.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StreamableHTTPTransport } from '@hono/mcp'
import { Hono } from 'hono'
const app = new Hono()
// Your MCP server implementation
const mcpServer = new McpServer({
name: 'my-mcp-server',
version: '1.0.0',
})
app.all('/mcp', async (c) => {
const transport = new StreamableHTTPTransport()
await mcpServer.connect(transport)
return transport.handleRequest(c)
})
Currently, this is ideal for creating stateless and authentication-less remote MCP servers.
Thanks @MathurAditya724!
The new @hono/ua-blocker middleware allows blocking requests based on user agent headers. It includes blocking AI bots functions.
import { uaBlocker } from '@hono/ua-blocker'
import { aiBots } from '@hono/ua-blocker/ai-bots'
import { Hono } from 'hono'
const app = new Hono()
// Block specific user agents
app.use(
'*',
uaBlocker({
blocklist: ['ForbiddenBot', 'Not You'],
})
)
// Block all AI bots
app.use(
'*',
uaBlocker({
blocklist: aiBots,
})
)
// Serve robots.txt to discourage AI bots
app.use('/robots.txt', useAiRobotsTxt())
Thanks @finxol!
The @hono/zod-validator middleware now supports Zod v4!
res.clone() is not supported by @yusukebe in https://github.com/honojs/hono/pull/4198res.clone() is not supported (#4198)" by @yusukebe in https://github.com/honojs/hono/pull/4200cacheableStatusCodes option by @miyamo2 in https://github.com/honojs/hono/pull/3943allow_anon option & passing Context to callbacks by @Beyondo in https://github.com/honojs/hono/pull/3961props to ExecutionContext by @yusukebe in https://github.com/honojs/hono/pull/4030NO_COLOR on cloudflare workers by @ryuapp in https://github.com/honojs/hono/pull/4094fire() by @yusukebe in https://github.com/honojs/hono/pull/4214app.fire() as deprecated by @yusukebe in https://github.com/honojs/hono/pull/4231Full Changelog: https://github.com/honojs/hono/compare/v4.7.11...v4.8.0
chore(benchmark): add URLSearchParams to the query-params benchmark by @yusukebe in https://github.com/honojs/hono/pull/4149
URLSearchParams to the query-params benchmark by @yusukebe in https://github.com/honojs/hono/pull/4149c.newResponse() for the response of err.getResponse() by @yusukebe in https://github.com/honojs/hono/pull/4181Full Changelog: https://github.com/honojs/hono/compare/v4.7.10...v4.7.11
fix(hono-base): copy notfound and error handlers in #clone() by @yusukebe in https://github.com/honojs/hono/pull/4139
#clone() by @yusukebe in https://github.com/honojs/hono/pull/4139header.alg as fallback in verifyFromJwks by @yusukebe in https://github.com/honojs/hono/pull/4144Full Changelog: https://github.com/honojs/hono/compare/v4.7.9...v4.7.10
fix(helper/cookie): correct getSignedCookie parameters type by @Hill-98 in https://github.com/honojs/hono/pull/4123
getSignedCookie parameters type by @Hill-98 in https://github.com/honojs/hono/pull/4123Full Changelog: https://github.com/honojs/hono/compare/v4.7.8...v4.7.9
chore(deps): bump wrangler to 4.12.0 by @yusukebe in https://github.com/honojs/hono/pull/4096
4.12.0 by @yusukebe in https://github.com/honojs/hono/pull/4096replaceRequest: false option for .mount by @geelen in https://github.com/honojs/hono/pull/4113Full Changelog: https://github.com/honojs/hono/compare/v4.7.7...v4.7.8
fix(trailing-slash): handle HEAD request in trailing slash middleware by @sushichan044 in https://github.com/honojs/hono/pull/4049
c.header() when it's finalized by @yusukebe in https://github.com/honojs/hono/pull/4078Full Changelog: https://github.com/honojs/hono/compare/v4.7.6...v4.7.7
fix(compress): avoid compressing if transfer-encoding is set by @usualoma in https://github.com/honojs/hono/pull/4027
hono is cool to hono is hot by @EdamAme-x in https://github.com/honojs/hono/pull/4035Full Changelog: https://github.com/honojs/hono/compare/v4.7.5...v4.7.6
docs(MIGRATION): Fix typo by @movahhedi in https://github.com/honojs/hono/pull/3999
BunWebSocketData and BunWebSocketHandler by @yusukebe in https://github.com/honojs/hono/pull/4002Full Changelog: https://github.com/honojs/hono/compare/v4.7.4...v4.7.5
fix(types): fix unhandled types for Deno 2.2 by @yusukebe in https://github.com/honojs/hono/pull/3977
Full Changelog: https://github.com/honojs/hono/compare/v4.7.3...v4.7.4
refactor: support TypeScript 5.7 for Deno 2.2 by @yusukebe in https://github.com/honojs/hono/pull/3939
BunWebSocketHandler by @yusukebe in https://github.com/honojs/hono/pull/3964Full Changelog: https://github.com/honojs/hono/compare/v4.7.2...v4.7.3
fix(proxy): fix header overwrite by @usualoma in https://github.com/honojs/hono/pull/3922
Request and Response classes by @BarryThePenguin in https://github.com/honojs/hono/pull/3928Full Changelog: https://github.com/honojs/hono/compare/v4.7.1...v4.7.2
refactor(helper/streaming): remove unused variables by @EdamAme-x in https://github.com/honojs/hono/pull/3904
next() by @usualoma in https://github.com/honojs/hono/pull/3905crypto by @EdamAme-x in https://github.com/honojs/hono/pull/3916Full Changelog: https://github.com/honojs/hono/compare/v4.7.0...v4.7.1
This release introduces one helper and two middleware.
Hono v4.7.0 is now available!
This release introduces one helper and two middleware.
Plus, Standard Schema Validator has been born.
Let's look at each of these.
We sometimes use the Hono application as a reverse proxy. In that case, it accesses the backend using fetch. However, it sends an unintended headers.
app.all('/proxy/:path', (c) => {
// Send unintended header values to the origin server
return fetch(`http://${originServer}/${c.req.param('path')}`)
})
For example, fetch may send Accept-Encoding, causing the origin server to return a compressed response. Some runtimes automatically decode it, leading to a Content-Length mismatch and potential client-side errors.
Also, you should probably remove some of the headers sent from the origin server, such as Transfer-Encoding.
Proxy Helper will send requests to the origin and handle responses properly. The above headers problem is solved simply by writing as follows.
import { Hono } from 'hono'
import { proxy } from 'hono/proxy'
app.get('/proxy/:path', (c) => {
return proxy(`http://${originServer}/${c.req.param('path')}`)
})
You can also use it in more complex ways.
app.get('/proxy/:path', async (c) => {
const res = await proxy(
`http://${originServer}/${c.req.param('path')}`,
{
headers: {
...c.req.header(),
'X-Forwarded-For': '127.0.0.1',
'X-Forwarded-Host': c.req.header('host'),
Authorization: undefined,
},
}
)
res.headers.delete('Set-Cookie')
return res
})
Thanks @usualoma!
Language Middleware provides 18n functions to Hono applications. By using the languageDetector function, you can get the language that your application should support.
import { Hono } from 'hono'
import { languageDetector } from 'hono/language'
const app = new Hono()
app.use(
languageDetector({
supportedLanguages: ['en', 'ar', 'ja'], // Must include fallback
fallbackLanguage: 'en', // Required
})
)
app.get('/', (c) => {
const lang = c.get('language')
return c.text(`Hello! Your language is ${lang}`)
})
You can get the target language in various ways, not just by using Accept-Language.
Accept-Language headerThanks @lord007tn!
Finally, middleware that supports JWK (JSON Web Key) has landed. Using JWK Auth Middleware, you can authenticate by verifying JWK tokens. It can access keys fetched from the specified URL.
import { Hono } from 'hono'
import { jwk } from 'hono/jwk'
app.use(
'/auth/*',
jwk({
jwks_uri: `https://${backendServer}/.well-known/jwks.json`,
})
)
app.get('/auth/page', (c) => {
return c.text('You are authorized')
})
Thanks @Beyondo!
Standard Schema provides a common interface for TypeScript validator libraries. Standard Schema Validator is a validator that uses it. This means that Standard Schema Validator can handle several validators, such as Zod, Valibot, and ArkType, with the same interface.
The code below really works!
import { Hono } from 'hono'
import { sValidator } from '@hono/standard-validator'
import { type } from 'arktype'
import * as v from 'valibot'
import { z } from 'zod'
const aSchema = type({
agent: 'string',
})
const vSchema = v.object({
slag: v.string(),
})
const zSchema = z.object({
name: z.string(),
})
const app = new Hono()
app.get(
'/:slag',
sValidator('header', aSchema),
sValidator('param', vSchema),
sValidator('query', zSchema),
(c) => {
const headerValue = c.req.valid('header')
const paramValue = c.req.valid('param')
const queryValue = c.req.valid('query')
return c.json({ headerValue, paramValue, queryValue })
}
)
const res = await app.request('/foo?name=foo', {
headers: {
agent: 'foo',
},
})
console.log(await res.json())
Thanks @muningis!
yarn by @EdamAme-x in https://github.com/honojs/hono/pull/3878toLowerCase() is unnecessary for req.header() by @yusukebe in https://github.com/honojs/hono/pull/3880env type by @yusukebe in https://github.com/honojs/hono/pull/3885c.json({}) by @yusukebe in https://github.com/honojs/hono/pull/3873deno.lock by @yusukebe in https://github.com/honojs/hono/pull/3897Full Changelog: https://github.com/honojs/hono/compare/v4.6.20...v4.7.0
refactor(helper/streaming): Avoid attaching AbortSignal on newer versions of Bun by @Jarred-Sumner in https://github.com/honojs/hono/pull/3859
np by @yusukebe in https://github.com/honojs/hono/pull/3874Full Changelog: https://github.com/honojs/hono/compare/v4.6.19...v4.6.20
fix(types): missing response type on OnHandlerInterface by @sor4chi in https://github.com/honojs/hono/pull/3852
OnHandlerInterface by @sor4chi in https://github.com/honojs/hono/pull/3852env should set c type correctly by @yusukebe in https://github.com/honojs/hono/pull/3856Full Changelog: https://github.com/honojs/hono/compare/v4.6.18...v4.6.19
perf(types): improve Utilities in types.ts by @yusukebe in https://github.com/honojs/hono/pull/3836
types.ts by @yusukebe in https://github.com/honojs/hono/pull/3836ParamKey simply by @yusukebe in https://github.com/honojs/hono/pull/3837factory.createMiddleware() by @yusukebe in https://github.com/honojs/hono/pull/3849Full Changelog: https://github.com/honojs/hono/compare/v4.6.17...v4.6.18
fix(helper/factory): Reduce the code size of createMiddleware by @miyaji255 in https://github.com/honojs/hono/pull/3824
Full Changelog: https://github.com/honojs/hono/compare/v4.6.16...v4.6.17
fix(jsx/dom): should not return memoized result when context is changed by @usualoma in https://github.com/honojs/hono/pull/3792
app.on(method,path[],middleware,handler) type by @yusukebe in https://github.com/honojs/hono/pull/3802Full Changelog: https://github.com/honojs/hono/compare/v4.6.15...v4.6.16
At first glance, this seems like a breaking change but not. It is not possible to return a contentless response with c.json() or c.text(). So, in that…
c.json() etc. throwing type error when the status is contentless code, e.g., 204From this release, when c.json(), c.text(), or c.html() returns content, specifying a contentless status code such as 204 will now throw a type error.
At first glance, this seems like a breaking change but not. It is not possible to return a contentless response with c.json() or c.text(). So, in that case, please use c.body().
app.get('/', (c) => {
return c.body(null, 204)
})
ResponseInit accepts generics StatusCode for status by @yusukebe in https://github.com/honojs/hono/pull/3770COMPOSED_HANDLER by @yusukebe in https://github.com/honojs/hono/pull/3773Full Changelog: https://github.com/honojs/hono/compare/v4.6.14...v4.6.15
perf(pattern-router): improve performance when create null object by @EdamAme-x in https://github.com/honojs/hono/pull/3730
Object.create(null) by @usualoma in https://github.com/honojs/hono/pull/3735charset parameter from MIME type of application/json by @SaekiTominaga in https://github.com/honojs/hono/pull/3743Full Changelog: https://github.com/honojs/hono/compare/v4.6.13...v4.6.14
chore: Add Cloudflare Static Assets reference to serveStatic deprecation notice by @ambergristle in https://github.com/honojs/hono/pull/3705
Array.prototype.at() to look at the end by @ryuapp in https://github.com/honojs/hono/pull/3703Full Changelog: https://github.com/honojs/hono/compare/v4.6.12...v4.6.13
ci(perf-measures): support KB by @EdamAme-x in https://github.com/honojs/hono/pull/3696
KB by @EdamAme-x in https://github.com/honojs/hono/pull/3696Full Changelog: https://github.com/honojs/hono/compare/v4.6.11...v4.6.12
docs: changed as even smaller by @EdamAme-x in https://github.com/honojs/hono/pull/3664
qs for query-param by @yusukebe in https://github.com/honojs/hono/pull/3674perf-measures by @yusukebe in https://github.com/honojs/hono/pull/3683build and perf-measures by @yusukebe in https://github.com/honojs/hono/pull/3686errorHandler with private not use # by @yusukebe in https://github.com/honojs/hono/pull/3692Full Changelog: https://github.com/honojs/hono/compare/v4.6.10...v4.6.11
chore: format no-response.yml by @yusukebe in https://github.com/honojs/hono/pull/3622
no-response.yml by @yusukebe in https://github.com/honojs/hono/pull/3622devDependencies by @EdamAme-x in https://github.com/honojs/hono/pull/3633package.json and jsr.json by @EdamAme-x in https://github.com/honojs/hono/pull/3638# for private props to reduce the minified bundle size by @EdamAme-x in https://github.com/honojs/hono/pull/3660c.req.routeIndex from being changed by @usualoma in https://github.com/honojs/hono/pull/3663Full Changelog: https://github.com/honojs/hono/compare/v4.6.9...v4.6.10
refactor: fix typos by @mattn in https://github.com/honojs/hono/pull/3583
c.req.param decodes invalid percent strings by @yusukebe in https://github.com/honojs/hono/pull/3573memo for DOM renderer by @usualoma in https://github.com/honojs/hono/pull/3568.concat instead of spread syntax by @EdamAme-x in https://github.com/honojs/hono/pull/3584any and fix types of adapter/deno by @EdamAme-x in https://github.com/honojs/hono/pull/3291.matchRoute and reduce bundle size by @EdamAme-x in https://github.com/honojs/hono/pull/3595c.redirect() by @cometkim in https://github.com/honojs/hono/pull/3609| 0 instead of Math.floor by @EdamAme-x in https://github.com/honojs/hono/pull/3605# for private methods to reduce the minified file size by @yusukebe in https://github.com/honojs/hono/pull/3596Full Changelog: https://github.com/honojs/hono/compare/v4.6.8...v4.6.9
fix(bun/ws): fix invalid types by @nakasyou in https://github.com/honojs/hono/pull/3562
--hot by @nakasyou in https://github.com/honojs/hono/pull/3576Full Changelog: https://github.com/honojs/hono/compare/v4.6.7...v4.6.8
fix(vercel): remove requestContext by @yusukebe in https://github.com/honojs/hono/pull/3549
requestContext by @yusukebe in https://github.com/honojs/hono/pull/3549Full Changelog: https://github.com/honojs/hono/compare/v4.6.6...v4.6.7
docs(powered-by): add JSDoc by @yusukebe in https://github.com/honojs/hono/pull/3520
NotFound warning on Deno by @pablo-abc in https://github.com/honojs/hono/pull/3542Full Changelog: https://github.com/honojs/hono/compare/v4.6.5...v4.6.6
This release includes a security fix for CSRF Protection Middleware. If you are using CSRF Protection Middleware, please upgrade this hono package imm…
This release includes a security fix for CSRF Protection Middleware. If you are using CSRF Protection Middleware, please upgrade this hono package immediately.
Before this release, a request without a Content-Type header can bypass the protection. This fix does not allow it. See: https://github.com/honojs/hono/security/advisories/GHSA-2234-fmw7-43wr
v2 by @yusukebe in https://github.com/honojs/hono/pull/3506Access-Control-Allow-Origin if there is no matching origin by @uki00a in https://github.com/honojs/hono/pull/3510Full Changelog: https://github.com/honojs/hono/compare/v4.6.4...v4.6.5
chore: upgrade dependencies by @yusukebe in https://github.com/honojs/hono/pull/3446
crypto-js from dev dependencies by @yusukebe in https://github.com/honojs/hono/pull/3447createMiddleware by @yusukebe in https://github.com/honojs/hono/pull/3498globalThis by @sapphi-red in https://github.com/honojs/hono/pull/3500override to toStringToBuffer in classes extending JSXNode by @yusukebe in https://github.com/honojs/hono/pull/3505Full Changelog: https://github.com/honojs/hono/compare/v4.6.3...v4.6.4
Your coding agent can read these notes before it upgrades. Set up the MCP server →