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
30 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
454 releases · first in 2021
One column per quarter.
Hono v3.9.0 is out now! Let's take a look at what's new.
Hono v3.9.0 is out now! Let's take a look at what's new.
Now we have the types for JSX.
Type definitions for JSX intrinsic elements are available. So, you can write your JSX with type annotation.
<img width="762" alt="Screenshot 2023-10-27 at 16 03 54" src="https://github.com/honojs/middleware/assets/10682/4e393324-aa8b-421b-bfab-8e3c59903a11">
<img width="322" alt="Screenshot 2023-10-27 at 16 04 30" src="https://github.com/honojs/middleware/assets/10682/bdf397e6-8d53-4370-a8d8-d2e28420c5e2">
You can also override the definitions to add your custom elements and attributes.
declare global {
namespace JSX {
interface IntrinsicElements {
'my-custom-element': Hono.HTMLAttributes & {
'x-event'?: 'click' | 'scroll'
}
}
}
}
Now Clerk Middleware is available! You can use Clerk for authentication in your application.
import { clerkMiddleware, getAuth } from '@hono/clerk-auth'
import { Hono } from 'hono'
const app = new Hono()
app.use('*', clerkMiddleware())
app.get('/', (c) => {
const auth = getAuth(c)
if (!auth?.userId) {
return c.json({
message: 'You are not logged in.'
})
}
return c.json({
message: 'You are logged in!',
userId: auth.userId
})
})
export default app
Thanks @octoper!
The Cloudflare Pages starter template is now Vite-based! You can develop truly full-stack applications quickly and fast thanks to Vite's HMR.
It uses Hono's original dev-server provided by @hono/vite-dev-server. And uses @hono/vite-cloudflare-pages for building the application. The config file is very neat.
import { defineConfig } from 'vite'
import devServer from '@hono/vite-dev-server'
import pages from '@hono/vite-cloudflare-pages'
export default defineConfig({
plugins: [
pages(),
devServer({
entry: 'src/index.tsx'
})
]
})
You can use it with the create hono command:
npm create hono@latest
The ecosystem has evolved. We introduce two products for Hono and one framework using Hono. Try them!
runtime option to env by @yusukebe in https://github.com/honojs/hono/pull/1622docType option by @yusukebe in https://github.com/honojs/hono/pull/1621Nothing published for this version
fix: combine fluent interface with route grouping by @ashtonsix in https://github.com/honojs/hono/pull/1610
Full Changelog: https://github.com/honojs/hono/compare/v3.8.3...v3.8.4
fix(jsx-renderer): fix PropsForRenderer by @yusukebe in https://github.com/honojs/hono/pull/1607
PropsForRenderer by @yusukebe in https://github.com/honojs/hono/pull/1607Full Changelog: https://github.com/honojs/hono/compare/v3.8.2...v3.8.3
fix(context): change FetchEvent detection way by @yusukebe in https://github.com/honojs/hono/pull/1595
FetchEvent detection way by @yusukebe in https://github.com/honojs/hono/pull/1595hono-base by @yusukebe in https://github.com/honojs/hono/pull/1604Full Changelog: https://github.com/honojs/hono/compare/v3.8.1...v3.8.2
fix: c.req.params() in nested app with custom error handler. by @usualoma in https://github.com/honojs/hono/pull/1593
c.req.params() in nested app with custom error handler. by @usualoma in https://github.com/honojs/hono/pull/1593Full Changelog: https://github.com/honojs/hono/compare/v3.8.0...v3.8.1
feat(app): basePath option for the constructor, deprecate app.basePath() by @yusukebe in https://github.com/honojs/hono/pull/1560
Hono v3.8.0 is out now! Let's take a look at the new features.
The new feature for JSX. By using useContext(), you can share data globally across any level of the Component tree without passing values through props.
import type { FC } from 'hono/jsx'
import { createContext, useContext } from 'hono/jsx'
const themes = {
light: {
color: '#000000',
background: '#eeeeee'
},
dark: {
color: '#ffffff',
background: '#222222'
}
}
const ThemeContext = createContext(themes.light)
const Button: FC = () => {
const theme = useContext(ThemeContext)
return <button style={theme}>Push!</button>
}
const Toolbar: FC = () => {
return (
<div>
<Button />
</div>
)
}
app.get('/', (c) => {
return c.html(
<div>
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
</div>
)
})
Thanks @usualoma!
JSX Renderer Middleware allows you to set up the layout when rendering JSX with the c.render() function, without the need for using c.setRenderer(). Additionally, it enables access to instances of Context within components through the use of useRequestContext().
import { Hono } from 'hono'
import { jsxRenderer, useRequestContext } from 'hono/jsx-renderer'
const app = new Hono()
const RequestUrlBadge: FC = () => {
const c = useRequestContext()
return <b>{c.req.url}</b>
}
app.get(
'/page/*',
jsxRenderer(({ children }) => {
return (
<html>
<body>
<nav>Menu</nav>
<div>{children}</div>
</body>
</html>
)
})
)
app.get('/page/about', (c) => {
return c.render(
<>
<h1>About me!</h1>
<div>
You are accessing: <RequestUrlBadge />
</div>
</>
)
})
Thanks @usualoma!
The streaming Helper provides a method to extend c.stream(). streamSSE() allows you to stream Server-Sent Events (SSE) seamlessly.
import { Hono } from 'hono'
import { streamSSE } from 'hono/streaming'
const app = new Hono()
app.get('/sse', async (c) => {
return streamSSE(c, async (stream) => {
while (true) {
const message = `It is ${new Date().toISOString()}`
await stream.writeSSE({ data: message })
await stream.sleep(1000)
}
})
})
Thanks @watany-dev!
The Factory Helper provides useful functions for creating Hono's components such as Middleware. Sometimes it's difficult to set the proper TypeScript types, but this helper facilitates that.
createMiddleware() that is added this version will create your custom middleware.
import { Hono } from 'hono'
import { createMiddleware } from 'hono/factory'
const messageMiddleware = createMiddleware(async (c, next) => {
await next()
c.res.headers.set('X-Message', 'Good morning!')
})
Thanks @arunavabasu-03 for helping!
parseBody() supports multi valuesNow, c.req.parseBody() supports multi values.
If the key is foo[], it will be (string | File)[].
const body = await c.req.parseBody()
body['foo[]']
And, you can use the all option.
const body = await c.req.parseBody({ all: true })
body['foo']
Thanks @sor4chi!
Improved the path matching in the router. Previously, for instance, a Duplicate param name error would be thrown if there were parameters with the same name, type, url, as shown below:
app.get('/:type/:url', (c) => {
return c.text(`type: ${c.req.param('type')}, url: ${c.req.param('url')}`)
})
app.get('/foo/:type/:url', (c) => {
return c.text(`foo type: ${c.req.param('type')}, url: ${c.req.param('url')}`)
})
With this improvement, the error is no longer thrown, and the correct parameter values can be obtained in each handler.
Thanks @usualoma!
parseBody() for multi values' field by @sor4chi in https://github.com/honojs/hono/pull/1528params per a handler (optimized for RegExpRouter) by @usualoma in https://github.com/honojs/hono/pull/1566basePath option for the constructor, deprecate app.basePath() by @yusukebe in https://github.com/honojs/hono/pull/1560package.json): export streaming helper by @yusukebe in https://github.com/honojs/hono/pull/1578factory helper for Deno by @yusukebe in https://github.com/honojs/hono/pull/1582basePath option for the constructor, deprecate app.basePath() (#1560)" by @yusukebe in https://github.com/honojs/hono/pull/1586hono-base by @yusukebe in https://github.com/honojs/hono/pull/1588Full Changelog: https://github.com/honojs/hono/compare/v3.7.6...v3.8.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
test: use Node.js Native Web APIs instead of miniflare's by @yusukebe in https://github.com/honojs/hono/pull/1558
instanceOf by @yusukebe in https://github.com/honojs/hono/pull/1565Full Changelog: https://github.com/honojs/hono/compare/v3.7.5...v3.7.6
fix(types): don't use webworker types by @yusukebe in https://github.com/honojs/hono/pull/1548
Full Changelog: https://github.com/honojs/hono/compare/v3.7.4...v3.7.5
fix(context): use FetchEvent instead of FetchEventLike by @yusukebe in https://github.com/honojs/hono/pull/1532
FetchEvent instead of FetchEventLike by @yusukebe in https://github.com/honojs/hono/pull/1532any casting by @yusukebe in https://github.com/honojs/hono/pull/1535Fragment correctly by @yusukebe in https://github.com/honojs/hono/pull/1541Full Changelog: https://github.com/honojs/hono/compare/v3.7.3...v3.7.4
fix(types): fix inferring path strings for an optional parameter with regexp by @yusukebe in https://github.com/honojs/hono/pull/1522
Full Changelog: https://github.com/honojs/hono/compare/v3.7.2...v3.7.3
fix(utils/buffer): fix bufferToFormData() by @yusukebe in https://github.com/honojs/hono/pull/1500
bufferToFormData() by @yusukebe in https://github.com/honojs/hono/pull/1500Full Changelog: https://github.com/honojs/hono/compare/v3.7.1...v3.7.2
fix(deno): export testing helper by @yusukebe in https://github.com/honojs/hono/pull/1493
testing helper by @yusukebe in https://github.com/honojs/hono/pull/1493Full Changelog: https://github.com/honojs/hono/compare/v3.7.0...v3.7.1
Hono v3.7.0 is out now! Let's take a look at the new features.
Hono v3.7.0 is out now! Let's take a look at the new features.
c.stream() and c.streamText()We added the awaited functionality related to streaming. c.stream() and c.streamText().
You can easily create HTTP Streaming endpoints with them.
app.get('/', (c) => {
return c.streamText(async (stream) => {
stream.writeln('Hello!')
await stream.sleep(1000)
stream.writeln('Hono!')
})
})
You know Streaming works well with AI. With streamText() you can write your ChatGPT Gateway in elegant code.
app.post('/api', async (c) => {
const body = await c.req.json<{ message: string }>()
const openai = new OpenAI({ apiKey: c.env.OPENAI_API_KEY })
const chatStream = await openai.chat.completions.create({
messages: PROMPT(body.message),
model: 'gpt-3.5-turbo',
stream: true
})
return c.streamText(async (stream) => {
for await (const message of chatStream) {
await stream.write(message.choices[0]?.delta.content ?? '')
}
})
})
This application can display streamed data from OpenAI's API in a flowing manner.
https://github.com/honojs/hono/assets/10682/cd40a23f-b780-4a8f-a754-3bd537f4682d
Thanks, @sor4chi and @geelen !
With testClient in Testing Helper you can easily write your tests. The object returned by this function is the hc client, so you can define your request with the editor completion.
import { testClient } from 'hono/testing'
it('test', async() => {
const app = new Hono().get('/search', (c) => c.jsonT({ hello: 'world' }))
const res = await testClient(app).search.$get()
expect(await res.json()).toEqual({ hello: 'world' })
})
https://github.com/honojs/hono/assets/10682/40876984-2c05-47f5-b1a8-c70cb8dc4261
Thanks, @hagishi !
We uses JWT functions internally, but now they are exported as JWT Helper. You can import and use them.
import { decode, sign, verify } from 'hono/jwt'
Thanks, @julianpoma !
enum by @yusukebe in https://github.com/honojs/hono/pull/1485c.stream() and c.streamText() matters by @yusukebe in https://github.com/honojs/hono/pull/1482Full Changelog: https://github.com/honojs/hono/compare/v3.6.3...v3.7.0
Nothing published for this version
Nothing published for this version
fix(types): return types of jsonT() should be union by @yusukebe in https://github.com/honojs/hono/pull/1471
jsonT() should be union by @yusukebe in https://github.com/honojs/hono/pull/1471Full Changelog: https://github.com/honojs/hono/compare/v3.6.2...v3.6.3
fix(types): Use ExpectTypeOf from vitest to test types by @vadhe in https://github.com/honojs/hono/pull/1458
string by @yusukebe in https://github.com/honojs/hono/pull/1470Full Changelog: https://github.com/honojs/hono/compare/v3.6.1...v3.6.2
fix(hono-base): deprecate should be deprecated by @yusukebe in https://github.com/honojs/hono/pull/1448
This release includes tiny features and bug fixes.
deprecate should be deprecated by @yusukebe in https://github.com/honojs/hono/pull/1448MiddlewareHandlerInterface by @yusukebe in https://github.com/honojs/hono/pull/1449Full Changelog: https://github.com/honojs/hono/compare/v3.6.0...v3.6.1
These properties in the HonoRequest have been deprecated.
Hono v3.6.0 is now available! Let's take a look at the new features.
c.render()We introduce c.render() and c.setRenderer() functions.
These functions enhance Hono's response handling, allowing for more flexible and modular response structures, especially useful for defining common parts of responses, like HTML layouts.
You can set a layout using c.setRenderer() within a custom middleware, as shown below:
app.use('*', async (c, next) => {
c.setRenderer((content) => {
return c.html(
<html>
<body>
<p>{content}</p>
</body>
</html>
)
})
await next()
})
Then, you can utilize c.render() to create responses within this layout:
app.get('/', (c) => {
return c.render('Hello!')
})
The output of which will be:
<html><body><p>Hello!</p></body></html>
Additionally, this feature offers the flexibility to customize arguments. To ensure type safety, types can be defined as:
declare module 'hono' {
interface ContextRenderer {
(content: string, head: { title: string }): Response
}
}
Here's an example of how you can use this:
app.use('/pages/*', async (c, next) => {
c.setRenderer((content, head) => {
return c.html(
<html>
<head>
<title>{head.title}</title>
</head>
<body>
<header>{head.title}</header>
<p>{content}</p>
</body>
</html>
)
})
await next()
})
app.get('/pages/my-favorite', (c) => {
return c.render(<p>Ramen and Sushi</p>, {
title: 'My favorite',
})
})
app.get('/pages/my-hobbies', (c) => {
return c.render(<p>Watching baseball</p>, {
title: 'My hobbies',
})
})
Using c.render() with JSX and html middleware, you can create HTML pages more easily!
c.varThe next feature we're introducing is c.var.
Before this release, to access the actual value of a variable, you had to use c.get():
const client = c.get('client')
Now, with c.var, a more intuitive syntax is available:
const result = c.var.client.oneMethod()
<img width="479" alt="Screenshot 2023-09-04 at 22 54 18" src="https://github.com/honojs/hono/assets/10682/b7b18848-cb69-4080-8a9c-3ee9bdfc1f92">
For instance, you can set an instance of the client for accessing an API with a middleware and then retrieve it using c.var.client:
const app = new Hono<{
Variables: {
client: Client
}
}>()
app.use('*', async (c, next) => {
c.set('client', new ApiClient())
await next()
})
app.get('/', (c) => {
const books = c.var.client.getBooks()
//...
})
FC for JSXThe type FC is exported from hono/jsx. You can use it to specify types for your function components.
import type { FC } from 'hono/jsx'
const Layout: FC<{ title: string }> = (props) => {
return (
<html>
<head>
<title>{props.title}</title>
</head>
<body>{props.children}</body>
</html>
)
}
const Top = (
<Layout title='Home page'>
<h1>Hono</h1>
<p>Hono is great</p>
</Layout>
)
$url() in Hono ClientYou can get a URL object for accessing the the endpoint by using $url().
const route = app.get('/api/foo/bar', (c) => c.jsonT({ foo: 'bar' }))
const client = hc<typeof route>('http://localhost:8787/')
const url = client.api.foo.bar.$url()
console.log(url.pathname) // `/api/foo/bar`
Thanks @renzor-fist !
Now, Hono offers a middleware factory method to create a middleware handler.
import { middleware } from 'hono/factory'
const mw = (message: string) =>
middleware(async (c, next) => {
await next()
c.header('X-Message', message)
})
By defining your middleware with middleware, the appropriate types will be added.
Now, we introduce a new Vite Plugin to enhance developing your Hono application.
@hono/vite-dev-server is a Vite Plugin that provides a custom dev-server for fetch-based web applications like those using Hono.
You can develop your application with Vite. It's fast.
fetch-based applications.https://github.com/honojs/vite-plugins/assets/10682/a93ee4c5-2e1a-4b17-8bb2-64f955f2f0b0
You can install vite and @hono/vite-dev-server via npm.
npm i -D vite @hono/vite-dev-server
Or you can install them with Bun.
bun add vite @hono/vite-dev-server
Add "type": "module" to your package.json. Then, create vite.config.ts and edit it.
import { defineConfig } from 'vite'
import devServer from '@hono/vite-dev-server'
export default defineConfig({
plugins: [
devServer({
entry: 'src/index.ts', // The file path of your application.
}),
],
})
Just run vite.
npm exec vite
Or
bunx --bun vite
Visit the GitHub project: https://github.com/honojs/vite-plugins/tree/main/packages/dev-server
These properties in the HonoRequest have been deprecated.
headers()body()bodyUsed()integrity()keepalive()referrer()signal()For instance, if you want to use headers, please use c.req.raw.headers().
This might not be a new feature, but it's a significant change.
We've switched the test framework used in Hono's core project from Jest to Vitest! It's fast!
<img width="446" alt="Screenshot 2023-09-11 at 7 49 07" src="https://github.com/honojs/hono/assets/10682/cb2aa7ac-6cff-4133-8ab3-3344cfaf53be">
Thanks @ThatOneBro for the great work!
status to TypedResponse by @ThatOneBro in https://github.com/honojs/hono/pull/1403c.render() by @yusukebe in https://github.com/honojs/hono/pull/1397c.req.headers (not c.req.header) and others by @yusukebe in https://github.com/honojs/hono/pull/1410RequestContext by @yusukebe in https://github.com/honojs/hono/pull/1421jest with vitest by @ThatOneBro in https://github.com/honojs/hono/pull/1404sandbox dir by @yusukebe in https://github.com/honojs/hono/pull/1424--no-warnings option for main by @yusukebe in https://github.com/honojs/hono/pull/1425MergeSchemaPath correct by @yusukebe in https://github.com/honojs/hono/pull/1426tsc before vitest by @yusukebe in https://github.com/honojs/hono/pull/1427$url() by @yusukebe in https://github.com/honojs/hono/pull/1430c.var by @yusukebe in https://github.com/honojs/hono/pull/1406FC by @yusukebe in https://github.com/honojs/hono/pull/1420factory helper by @yusukebe in https://github.com/honojs/hono/pull/1434Full Changelog: https://github.com/honojs/hono/compare/v3.5.8...v3.6.0
Nothing published for this version
Nothing published for this version
fix(rpc): infer path with route() and basePath() by @yusukebe in https://github.com/honojs/hono/pull/1401
route() and basePath() by @yusukebe in https://github.com/honojs/hono/pull/1401utils/buffer): don't decode space as + by @yusukebe in https://github.com/honojs/hono/pull/1411Fragment by @yusukebe in https://github.com/honojs/hono/pull/1412Full Changelog: https://github.com/honojs/hono/compare/v3.5.7...v3.5.8
improvements to secure headers middleware by @jkeys089 in https://github.com/honojs/hono/pull/1395
arrayBuffer to use after validation by @yusukebe in https://github.com/honojs/hono/pull/1393Full Changelog: https://github.com/honojs/hono/compare/v3.5.6...v3.5.7
fix(types): infer a response type for async handler by @yusukebe in https://github.com/honojs/hono/pull/1385
Full Changelog: https://github.com/honojs/hono/compare/v3.5.5...v3.5.6
ci: check if it is denoified by @yusukebe in https://github.com/honojs/hono/pull/1378
package.json): export hono/context" by @yusukebe in https://github.com/honojs/hono/pull/1381jsonT() by @yusukebe in https://github.com/honojs/hono/pull/1379Full Changelog: https://github.com/honojs/hono/compare/v3.5.4...v3.5.5
fix(types): fix AddDollar by @yusukebe in https://github.com/honojs/hono/pull/1373
Sorry so often!
AddDollar by @yusukebe in https://github.com/honojs/hono/pull/1373Full Changelog: https://github.com/honojs/hono/compare/v3.5.3...v3.5.4
fix(types): export ToSchema by @yusukebe in https://github.com/honojs/hono/pull/1372
ToSchema by @yusukebe in https://github.com/honojs/hono/pull/1372Full Changelog: https://github.com/honojs/hono/compare/v3.5.2...v3.5.3
fix(types): remove type-errors for routes by @yusukebe in https://github.com/honojs/hono/pull/1371
Full Changelog: https://github.com/honojs/hono/compare/v3.5.1...v3.5.2
fix(client): continue if query value is undefined by @yusukebe in https://github.com/honojs/hono/pull/1368
continue if query value is undefined by @yusukebe in https://github.com/honojs/hono/pull/1368content-length header by @yusukebe in https://github.com/honojs/hono/pull/1366Full Changelog: https://github.com/honojs/hono/compare/v3.5.0...v3.5.1
However, no worries about breaking changes! The import path hono/cookie remains unchanged. So, usage remains consistent with previous versions.
Hono v3.5.0 is now available! Here's what's new.
We've added the Secure Headers Middleware. It aids in enhancing your app's security by setting HTTP response headers. It's akin to Helmet for Express.
import { Hono } from 'hono'
import { secureHeaders } from 'hono/secure-headers'
const app = new Hono()
app.use('*', secureHeaders())
app.get('/', (c) => c.text('Hello!'))
// ...
export default app
For an in-depth look, visit the documentation. Thanks @watany-dev for the remarkable contribution!
We're unveiling a new concept named "Helpers". While similar to middleware, these are not handlers but handy functions. Prior to this release, the cookie-related functions were a part of the Cookie Middleware. These aren't true middleware. Now, they've been transformed into the "Cookie Helper":
import { getCookie, setCookie } from 'hono/cookie'
const app = new Hono()
app.get('/cookie', (c) => {
const yummyCookie = getCookie(c, 'yummy_cookie')
// ...
setCookie(c, 'delicious_cookie', 'macha')
// ...
})
However, no worries about breaking changes! The import path hono/cookie remains unchanged. So, usage remains consistent with previous versions.
Zod OpenAPI has been rolled out. Zod OpenAPI Hono is an enhanced Hono class supporting OpenAPI. It enables value and type validation using Zod and also facilitates OpenAPI Swagger documentation generation.
Dive deeper with the documentation.
The following features are now marked as deprecated:
queries in the Validator - Please switch to query.c.runtime() - Transition to the Adapter Helper.app.handleEvent() - Use app.fetch() instead.These will be removed in version 4.
env to getPath(). https://github.com/honojs/hono/pull/1345hono/context has been exported. https://github.com/honojs/hono/pull/1332format script by @watany-dev in https://github.com/honojs/hono/pull/1334package.json): export hono/context by @yusukebe in https://github.com/honojs/hono/pull/1332HonoRequest as 1st arg by @yusukebe in https://github.com/honojs/hono/pull/1312req.valid() by @yusukebe in https://github.com/honojs/hono/pull/1351queries (use query instead) by @yusukebe in https://github.com/honojs/hono/pull/1350header and cookie by @yusukebe in https://github.com/honojs/hono/pull/1352env to getPath() by @yusukebe in https://github.com/honojs/hono/pull/1345header and cookie types by @yusukebe in https://github.com/honojs/hono/pull/1359Context methods by @asaxeye in https://github.com/honojs/hono/pull/1357middleware.ts): export secure-headers for Deno by @yusukebe in https://github.com/honojs/hono/pull/1361Full Changelog: https://github.com/honojs/hono/compare/v3.4.3...v3.5.0
Nothing published for this version
fix(app): set / for path as default by @yusukebe in https://github.com/honojs/hono/pull/1330
/ for path as default by @yusukebe in https://github.com/honojs/hono/pull/1330Full Changelog: https://github.com/honojs/hono/compare/v3.4.2...v3.4.3
Add missing wasm mime type by @timfish in https://github.com/honojs/hono/pull/1307
constructor.name instead of instanceof by @yusukebe in https://github.com/honojs/hono/pull/1311c.req.param() by @yusukebe in https://github.com/honojs/hono/pull/1329Full Changelog: https://github.com/honojs/hono/compare/v3.4.1...v3.4.2
fix(netlify): fix import paths by @yusukebe in https://github.com/honojs/hono/pull/1304
Full Changelog: https://github.com/honojs/hono/compare/v3.4.0...v3.4.1
refactor(app): add "deprecate message" for app.handleEvent() by @yusukebe in https://github.com/honojs/hono/pull/1298
v3.4.0 is out now! This release includes two significant new features.
We're introducing the Netlify Adapter! With this adapter, you can run your Hono application on Netlify Edge Functions.
import { Hono } from 'https://deno.land/x/hono@v3.4.1/mod.ts'
import { prettyJSON } from 'https://deno.land/x/hono@v3.4.1/middleware.ts'
import { handle, type Env } from 'https://deno.land/x/hono@v3.4.1/adapter/netlify/mod.ts'
const app = new Hono<Env>()
app.get('/', prettyJSON(), (c) =>
c.json({
'You are in': c.env.context.geo.country?.name
})
)
export default handle(app)
You can try it with the create-hono command:
npm create hono@latest my-app
Additionally, we now have 12 starter templates, ensuring that Hono runs on various platforms.
Hono really runs on every platforms.
Cookie Middleware now supports signed cookies. You can use getSignedCookie() and setSignedCookie() helper functions.
app.get('/signed-cookie', async (c) => {
const secret = 'secret ingredient'
const allSignedCookies = await getSignedCookie(c, secret)
const fortuneCookie = await getSignedCookie(c, secret, 'fortune_cookie')
// ...
const anotherSecret = 'secret chocolate chips'
await setSignedCookie(c, 'great_cookie', 'blueberry', anotherSecret)
deleteCookie(c, 'great_cookie')
//
})
Special thanks to @torte for this feature!
jest.config.js by @yusukebe in https://github.com/honojs/hono/pull/1274app.request by @yusukebe in https://github.com/honojs/hono/pull/1275indexOf() by @yusukebe in https://github.com/honojs/hono/pull/1276init flag by @yusukebe in https://github.com/honojs/hono/pull/1284parseBody() by @yusukebe in https://github.com/honojs/hono/pull/1289app.route() JSDoc description by @yusukebe in https://github.com/honojs/hono/pull/1296app.handleEvent() by @yusukebe in https://github.com/honojs/hono/pull/1298Full Changelog: https://github.com/honojs/hono/compare/v3.3.4...v3.4.0
This release includes important security fixes.
This release includes important security fixes.
If you are using serveStatic() with Bun, you must upgrade to this version immediately. Alternatively, you can install the upcoming Bun release, which will include relevant fixes related to this issue.
You can do so using the following commands:
npm install hono@latest
Or
yarn upgrade hono@latest
Also, fixes have been made to the JSX middleware. If you're using this, please ensure that you upgrade it as well.
.. in filename by @yusukebe in https://github.com/honojs/hono/pull/1272serveStatic() by @yusukebe in https://github.com/honojs/hono/pull/1273Full Changelog: https://github.com/honojs/hono/compare/v3.3.3...v3.3.4
This release introduces a small new feature, but it's being rolled out as a patch-release.
This release introduces a small new feature, but it's being rolled out as a patch-release.
strict with getPath option by @yusukebe in https://github.com/honojs/hono/pull/1259Full Changelog: https://github.com/honojs/hono/compare/v3.3.2...v3.3.3
refactor(etag): simplify cloning logic by @jamesarosen in https://github.com/honojs/hono/pull/1242
Full Changelog: https://github.com/honojs/hono/compare/v3.3.1...v3.3.2
fix(lambda): avoid UTF-8-encoding binary data by @denisw in https://github.com/honojs/hono/pull/1235
Full Changelog: https://github.com/honojs/hono/compare/v3.3.0...v3.3.1
v3.3.0 is now available. This release includes two new features. Let's explore them.
v3.3.0 is now available. This release includes two new features. Let's explore them.
Performance measurement is important. We're introducing the Server-Timing Middleware. This middleware allows you to measure the performance of processes in handlers using the Server-Timing API.
import { Hono } from 'hono'
import { endTime, setMetric, startTime, timing } from 'hono/timing'
const app = new Hono()
app.use('*', timing())
app.get('/', async (c) => {
// add custom metrics
setMetric(c, 'region', 'europe-west3')
// add custom metrics with timing, must be in milliseconds
setMetric(c, 'custom', 23.8, 'My custom Metric')
// start a new timer
startTime(c, 'db')
const data = ['foo'] // DB process
endTime(c, 'db')
return c.json({ response: data })
})
export default app
You can view the results in tools like Chrome DevTools.
Thanks to @PassiDel for contributing!
We already have an AWS Lambda adapter, but it did not support Lambda@Edge. Now, the Lambda@Edge Adapter is available, although it's experimental. It's easy to use.
import { Hono } from 'hono'
import { handle } from 'hono/lambda-edge'
const app = new Hono()
app.get('/', (c) => c.text('Hello Hono!'))
export const handler = handle(app)
If you want to add Basic Auth and continue with request processing after verification, you can use c.env.callback()
import { Callback, CloudFrontRequest, handle } from 'hono/lambda-edge'
type Bindings = {
callback: Callback
request: CloudFrontRequest
}
const app = new Hono<{ Bindings: Bindings }>()
app.get(
'*',
basicAuth({
username: 'a',
password: 'b'
})
)
app.get('/index.html', async (c, next) => {
await next()
c.env.callback(null, c.env.request)
})
export const handler = handle(app)
Special thanks to @watany-dev for this feature!
context and callback as env by @yusukebe in https://github.com/honojs/hono/pull/1229Full Changelog: https://github.com/honojs/hono/compare/v3.2.7...v3.3.0
Nothing published for this version
fix(utils/cookie): allow 0 to maxAge by @yusukebe in https://github.com/honojs/hono/pull/1196
skipLibCheck by @yusukebe in https://github.com/honojs/hono/pull/1201skipLibCheck by @yusukebe in https://github.com/honojs/hono/pull/1206jsonT): remove overloads from JSONTRespond by @yusukebe in https://github.com/honojs/hono/pull/1208Full Changelog: https://github.com/honojs/hono/compare/v3.2.6...v3.2.7
fix: application/x-www-form-urlencoded decoding by @klittlepage in https://github.com/honojs/hono/pull/1189
maxAge should be positive by @yusukebe in https://github.com/honojs/hono/pull/1194Full Changelog: https://github.com/honojs/hono/compare/v3.2.5...v3.2.6
feat: Allow context.jsonT to take interface as an argument by @ayame113 in https://github.com/honojs/hono/pull/1162
context.jsonT to take interface as an argument by @ayame113 in https://github.com/honojs/hono/pull/1162style conversion by @yusukebe in https://github.com/honojs/hono/pull/1159Full Changelog: https://github.com/honojs/hono/compare/v3.2.4...v3.2.5
This release includes a "small" breaking change.
This release includes a "small" breaking change.
Before this release, if a HEAD request was received, the app would handle it with the handler defined in app.head(). If there were no preferred handlers, it would return "Not Found".
app.head('/foo', (c) => {
return new Response(null, {
headers: {
Foo: 'Bar',
},
})
})
This would handle:
HEAD /foo
Since this release, app.head() will not be enabled. Instead, the app will automatically return the responses for HEAD requests if it has a preferred app.get() handler. This means you don't have to set the handlers for HEAD explicitly.
const app = new Hono()
app.get('/', (c) => {
return c.text('Foo')
})
export default app
$ curl --head http://localhost:8787/
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
If you want to customize the response for HEAD method, write like the following:
app.get('/', (c) => {
if (c.req.method === 'HEAD') {
return new Response(null, {
headers: {
'Content-Length': '12345',
},
})
}
return c.text('Foo')
})
You can still use app.head(), but it will not have any effect. So, you should remove them.
indexOf() intead of includes() by @yusukebe in https://github.com/honojs/hono/pull/1150Full Changelog: https://github.com/honojs/hono/compare/v3.2.3...v3.2.4
fix: Add missing client types and TypedResponse type by @dimik in https://github.com/honojs/hono/pull/1135
Full Changelog: https://github.com/honojs/hono/compare/v3.2.2...v3.2.3
fix(basic-auth): handle passing invalid value to atob() by @yusukebe in https://github.com/honojs/hono/pull/1122
This is a patch release.
atob() by @yusukebe in https://github.com/honojs/hono/pull/1122PatternRouter and LinearRouter by @yusukebe in https://github.com/honojs/hono/pull/1128headers.append(), use headers.set() by @yusukebe in https://github.com/honojs/hono/pull/1129Full Changelog: https://github.com/honojs/hono/compare/v3.2.1...v3.2.2
fix(app): app.mount() supports / by @yusukebe in https://github.com/honojs/hono/pull/1119
This is a patch release.
app.mount() supports / by @yusukebe in https://github.com/honojs/hono/pull/1119Full Changelog: https://github.com/honojs/hono/compare/v3.2.0...v3.2.1
And c.req.cookie() and c.cookie() are deprecated and will be removed in the next major version, *v4*.
New routers, presets,
app.mount(), Node server v1. Let's go!
Hono v3.2 is now available! It introduces many features while maintaining simplicity.
hono/tiny, hono/quick.app.mount()hono/nextjs to hono/vercel.Let's take a look!
We introduce two new routers: LinearRouter and PatternRouter.
LinearRouter is "quick". While RegExpRouter is one of the fastest routers in the JavaScript world, it's a bit slow when registering routing paths.
app.get('/', handler) // <=== Registering routing paths - a little slow
//...
app.fetch(request) // <=== Handle request - ultra-fast
So, in environments that are initialized with every request, such as Fastly Compute@Edge, RegExpRouter may not be the best choice.
LinearRouter registers routes very quickly, even compared to other fast JavaScript routers. The following is one of the benchmark results, which includes the route registration phase.
• GET /user/lookup/username/hey
----------------------------------------------------- -----------------------------
LinearRouter 1.82 µs/iter (1.7 µs … 2.04 µs) 1.84 µs 2.04 µs 2.04 µs
MedleyRouter 4.44 µs/iter (4.34 µs … 4.54 µs) 4.48 µs 4.54 µs 4.54 µs
FindMyWay 60.36 µs/iter (45.5 µs … 1.9 ms) 59.88 µs 78.13 µs 82.92 µs
KoaTreeRouter 3.81 µs/iter (3.73 µs … 3.87 µs) 3.84 µs 3.87 µs 3.87 µs
TrekRouter 5.84 µs/iter (5.75 µs … 6.04 µs) 5.86 µs 6.04 µs 6.04 µs
summary for GET /user/lookup/username/hey
LinearRouter
2.1x faster than KoaTreeRouter
2.45x faster than MedleyRouter
3.21x faster than TrekRouter
33.24x faster than FindMyWay
And according to this comment, it will be 40% faster on Fastly Compute@Edge.
PatternRouter is "tiny". By default, Hono uses SmartRouter with RegExpRouter and TrieRouter. Although not the fastest, we made it even smaller.
If you need to reduce size for resource-limited environments, you can use PatternRouter.
An application using only PatternRouter is about 12KB in size.
yusuke $ esbuild --outdir=dist --bundle --minify ./src/index.ts
dist/index.js 11.9kb
⚡ Done in 9ms
hono/tiny, hono/quickHono has several routers, each designed for a specific purpose. You can specify the router you want to use in the Hono constructor.
Presets are provided for common use cases, so you don't have to specify the router each time. The Hono class imported from all presets is the same, the only difference being the router. Therefore, you can use them interchangeably.
We introduce hono/tiny and hono/quick today.
hono/tinyPreset hono/tiny means using only PatternRouter.
this.router = new PatternRouter()
To use hono/tiny, you only have to import hono/tiny and use Hono as usual.
import { Hono } from 'hono/tiny'
const app = new Hono()
//...
hono/quickPreset hono/quick means using only LinearRouter.
this.router = new LinearRouter()
You can also use hono/quick like other presets.
import { Hono } from 'hono/quick'
We now offer three presets: hono, hono/tiny, and hono/quick. You might be wondering, "Which preset should I use?" Please refer to the followings.
| Preset | Suitable platforms |
|---|---|
hono |
This is highly recommended for most use cases. Although the registration phase may be slower than hono/quick, it exhibits high performance once booted. It's ideal for long-life servers built with Deno, Bun, or Node.js. For environments such as Cloudflare Workers, Deno Deploy, Lagon, where v8 isolates are utilized, this preset is suitable too. Because the isolates persist for a certain amount of time after booting. |
hono/quick |
This preset is designed for environments where the application is initialized for every request. Fastly Compute@Edge operates in this manner, thus this preset is recommended for use it. |
hono/tiny |
This is the smallest router package and is suitable for environments where resources are limited. |
app.mount()By using new feature app.mount(), you can integrate applications using other frameworks, such as itty-router, with Hono.
// Create itty-router application
const ittyRouter = IttyRouter()
// Handle `GET /itty-router/hello`
ittyRouter.get('/hello', () => new Response('Hello from itty-router!'))
// Hono application
const app = new Hono()
// Hono application
app.mount('/itty-router', ittyRouter.handle)
Also Remix:
import { Hono } from 'hono'
import { env } from 'hono/adapter'
import { serveStatic } from 'hono/cloudflare-workers'
import { createRequestHandler } from '@remix-run/cloudflare'
import * as build from './build'
// Remix application
// @ts-ignore
const handleRemixRequest = createRequestHandler(build, process.env.NODE_ENV)
// Hono application
const app = new Hono()
// Static files for Remix
app.get(
'/remix/build/*',
serveStatic({
root: './',
})
)
// Mount Remix app
app.mount('/remix', handleRemixRequest, (c) => {
return { env: env(c) }
})
This implies that we can mount applications built with any framework, such as itty-router, Remix, Qwik, or SolidJS, into our Hono application.
With this implementation, we introduce two concepts: adapt and mount. Adapt refers to Hono's ability to adapt to any runtime, while mount implies that Hono can integrate with any framework. Along with middleware, these capabilities allow us to create a comprehensive ecosystem, as depicted below:
With these special features, Hono will not just be a web framework, it will be like a "Glue".
One of the greatest aspects of this concept is that the framework does not have to create individual adapters for various platforms such as Cloudflare Worker, Cloudflare Pages, Vercel, Deno, and Bun.
If your framework is based on the Web Standard API, there is no additional work required. Hono can mount it and enable your framework to run on any runtime.
Furthermore, we can use Hono's middleware for other frameworks. For example, to add Basic authentication to an application built with ittry-router, there's no need to implement it from scratch. Just add Hono's middleware.
app.use('/another-app/admin/*', basicAuth({ username, password }))
This is the ecosystem we wanted creating.
The first major release of the Node.js adapter server, "v1.0.0", is now available! This version uses only the native Web Standard APIs available in Node.js v18 or higher. The size has been significantly reduced and this means we are really following to Web Standard APIs.
You can start using it right away by installing it from npm.
npm install @hono/node-server
Then, simply import the serve function and adapt it to your Hono application.
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono meets Node.js'))
serve(app, (info) => {
console.log(`Listening on http://localhost:${info.port}`)
})
The new getPath() function now supports routing that includes a hostname.
const app = new Hono({
getPath: (req) => req.url.replace(/^https?:\/\//, ''),
})
app.get('www1.example.com/hello', (c) => c.text('hello www1'))
app.get('www2.example.com/hello', (c) => c.text('hello www2'))
With getPath(), you can also handle the host header value for routing.
const app = new Hono({
getPath: (req) => req.headers.get('host') + req.url.replace(/^https?:\/\/[^\/]+/, ''),
})
app.get('www1.example.com/hello', (c) => c.text('hello www1'))
// The following request will match the route:
// new Request('http://www1.example.com/hello', {
// headers: { host: 'www1.example.com' },
// })
The AWS Lambda adapter now supports Lambda functions URLs.
We're introducing a new Cookie Middleware.
import { getCookie, setCookie } from 'hono/cookie'
// ...
app.get('/cookie', (c) => {
const yummyCookie = getCookie(c, 'yummy_cookie')
// ...
setCookie(c, 'delicious_cookie', 'macha')
//
}
And c.req.cookie() and c.cookie() are deprecated and will be removed in the next major version, v4.
hono/nextjs to hono/vercelWe've created hono/vercel and deprecated hono/nextjs. hono/nextjs will be removed in v4.
rewriteRequestPath option for the serve-staticapp.routerNamehttp-status.tsThank you to all our contributors!
=== instead of startsWith and endsWith by @yusukebe in https://github.com/honojs/hono/pull/1053HTTPException from mod.ts by @yusukebe in https://github.com/honojs/hono/pull/1058runtime_tests by @yusukebe in https://github.com/honojs/hono/pull/1062rewriteRequestPath option for Workers/Deno/Bun by @yusukebe in https://github.com/honojs/hono/pull/1065jsx-runtime bug by @yusukebe in https://github.com/honojs/hono/pull/1070c.header(key, undefined) by @yusukebe in https://github.com/honojs/hono/pull/1071c.req.cookie() / c.cookie() by @yusukebe in https://github.com/honojs/hono/pull/1066hono/vercel / deprecate hono/nextjs by @yusukebe in https://github.com/honojs/hono/pull/1073ContextVarableMap by @yusukebe in https://github.com/honojs/hono/pull/1080hono/quick by @yusukebe in https://github.com/honojs/hono/pull/1074type.ts by @yusukebe in https://github.com/honojs/hono/pull/1082rewriteRequestPath option by @yusukebe in https://github.com/honojs/hono/pull/1098onError() supports async by @yusukebe in https://github.com/honojs/hono/pull/1090/ for generics basePath by @yusukebe in https://github.com/honojs/hono/pull/1083fire() correctly by @yusukebe in https://github.com/honojs/hono/pull/1106setup-bun by @yusukebe in https://github.com/honojs/hono/pull/1108app.routerName() by @yusukebe in https://github.com/honojs/hono/pull/1105app.mount() by @yusukebe in https://github.com/honojs/hono/pull/1104PatternRouter supports a hostname, added tests by @yusukebe in https://github.com/honojs/hono/pull/1114Full Changelog: https://github.com/honojs/hono/compare/v3.1.8...v3.2.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
empty string is a valid header value by @AlexErrant in https://github.com/honojs/hono/pull/1056
global.fastly instead of require('fastly:env') by @yusukebe in https://github.com/honojs/hono/pull/1057Full Changelog: https://github.com/honojs/hono/compare/v3.1.7...v3.1.8
fix(context): Fix typo in charset. by @usualoma in https://github.com/honojs/hono/pull/1046
Full Changelog: https://github.com/honojs/hono/compare/v3.1.6...v3.1.7
fix(pages): fixed type mismatch in EventContext by @yusukebe in https://github.com/honojs/hono/pull/1026
This is a small fix.
EventContext by @yusukebe in https://github.com/honojs/hono/pull/1026Full Changelog: https://github.com/honojs/hono/compare/v3.1.5...v3.1.6
Your coding agent can read these notes before it upgrades. Set up the MCP server →