v4.12.0

honojs/honov4.12.0Feb 19, 2026by yusukebe

AI Summary

A feature-rich release with new client capabilities, middleware improvements, adapter enhancements, and significant performance optimizations including 1.5x-2x faster TrieRouter and 10.6% improved JSON throughput.

Key Highlights

  • $path method for Hono Client - returns path string for routing and cache keys
  • ApplyGlobalResponse type helper for adding global error response types to RPC client
  • SSG redirect plugin for generating static HTML redirect pages
  • onAuthSuccess callback for Basic Auth middleware
  • getConnInfo available for AWS Lambda, Cloudflare Pages, and Netlify adapters
  • alwaysRedirect option for trailing slash middleware with wildcard routes
  • Progressive locale code truncation in language middleware
  • TrieRouter performance improved 1.5x-2.0x across all runtimes
  • Fast path optimization for c.json() with 10.6% throughput improvement

New Features

  • $path() method for Hono Client
  • ApplyGlobalResponse type helper for RPC Client
  • SSG redirect plugin
  • onAuthSuccess callback for Basic Auth
  • getConnInfo for AWS Lambda, Cloudflare Pages, and Netlify
  • alwaysRedirect option for trailing slash middleware
  • Progressive locale code truncation for language middleware
  • exports field for ExecutionContext in Cloudflare Workers

Full Release Notes

# Release Notes

Hono v4.12.0 is now available!

This release includes new features for the Hono client, middleware improvements, adapter enhancements, and significant performance improvements to the router and context.

## `$path` for Hono Client

The Hono client now has a `$path()` method that returns the path string instead of a full URL. This is useful when you need just the path portion for routing or key-based operations:

```ts
const client = hc<typeof app>('http://localhost:8787')

// Get the path string
const path = client.api.posts.$path()
// => '/api/posts'

// With path parameters
const postPath = client.api.posts[':id'].$path({
  param: { id: '123' },
})
// => '/api/posts/123'

// With query parameters
const searchPath = client.api.posts.$path({
  query: { filter: 'test' },
})
// => '/api/posts?filter=test'
```

Unlike `$url()` which returns a `URL` object, `$path()` returns a plain path string, making it convenient for use with routers or as cache keys.

Thanks @ShaMan123!

## `ApplyGlobalResponse` Type Helper for RPC Client

The new `ApplyGlobalResponse` type helper allows you to add global error response types to all routes in the RPC client. This is useful for typing common error responses from `app.onError()` or global middlewares:

```ts
const app = new Hono()
  .get('/api/users', (c) => c.json({ users: ['alice', 'bob'] }, 200))
  .onError((err, c) => c.json({ error: err.message }, 500))

type AppWithErrors = ApplyGlobalResponse<
  typeof app,
  {
    401: { json: { error: string; message: string } }
    500: { json: { error: string; message: string } }
  }
>

const client = hc<AppWithErrors>('http://api.example.com')
// Now client knows about both success and error responses
const res = await client.api.users.$get()
// InferResponseType includes { users: string[] } | { error: string; message: string }
```

Thanks @mohankumarelec!

## SSG Redirect Plugin

A new `redirectPlugin` for SSG generates static HTML redirect pages for HTTP redirect responses (301, 302, 303, 307, 308):

```ts
import { toSSG } from 'hono/ssg'
import { defaultPlugin, redirectPlugin } from 'hono/ssg'

const app = new Hono()
app.get('/old', (c) => c.redirect('/new'))
app.get('/new', (c) => c.html('New Page'))

// redirectPlugin must be placed before defaultPlugin
await toSSG(app, fs, {
  plugins: [redirectPlugin(), defaultPlugin()],
})
```

The generated redirect pages include a `<meta http-equiv="refresh">` tag, a canonical link, and a `robots noindex` meta tag.

Thanks @3w36zj6!

## `onAuthSuccess` Callback for Basic Auth

The Basic Auth middleware now supports an `onAuthSuccess` callback that is invoked after successful authentication. This allows you to set context variables or perform logging without re-parsing the Authorization header:

```ts
app.use(
  '/auth/*',
  basicAuth({
    username: 'hono',
    password: 'ahotproject',
    onAuthSuccess: (c, username) => {
      c.set('user', { name: username, role: 'admin' })
      console.log(`User ${username} authenticated`)
    },
  })
)
```

The callback also works with async functions and the `verifyUser` mode.

Thanks @AprilNEA!

## `getConnInfo` for AWS Lambda, Cloudflare Pages, and Netlify

`getConnInfo()` is now available for three additional adapters:

```ts
// AWS Lambda (supports API Gateway v1, v2, and ALB)
import { handle, getConnInfo } from 'hono/aws-lambda'

// Cloudflare Pages
import { handle, getConnInfo } from 'hono/cloudflare-pages'

// Netlify
import { handle, getConnInfo } from 'hono/netlify'

app.get('/', (c) => {
  const info = getConnInfo(c)
  return c.text(`Your IP: ${info.remote.address}`)
})
```

Thanks @rokasta12!

## `alwaysRedirect` Option for Trailing Slash Middleware

The trailing slash middleware now supports an `alwaysRedirect` option. When enabled, the middleware redirects before executing handlers, which fixes the issue where trailing slash handling doesn't work with wildcard routes:

```ts
app.use(trimTrailingSlash({ alwaysRedirect: true }))

app.get('/my-path/*', async (c) => {
  return c.text('wildcard')
})

// /my-path/something/ will be redirected to /my-path/something
// before the wildcard handler is executed
```

## Progressive Locale Code Truncation

The `normalizeLanguage` function in the language middleware now supports RFC 4647 Lookup-based progressive truncation. Locale codes like `ja-JP` will match `ja` when only the base language is in `supportedLanguages`:

```ts
app.use(
  '/*',
  languageDetector({
    supportedLanguages: ['en', 'ja'],
    fallbackLanguage: 'en',
    order: ['cookie', 'header'],
  })
)

// Accept-Language: ja-JP → matches 'ja'
// Accept-Language: ko-KR → falls back to 'en'
```

Thanks @sorafujitani!

## `exports` Field for `ExecutionContext`

The `ExecutionContext` type now includes an `exports` property for Cloudflare Workers. You can use module augmentation to type it with Wrangler's generated types:

```ts
import 'hono'

declare module 'hono' {
  interface ExecutionContext {
    readonly exports: Cloudflare.Exports
  }
}
```

Thanks @toreis-up!

## Performance Improvements

### TrieRouter 1.5x ~ 2.0x Faster

The TrieRouter has been significantly optimized with reduced spread syntax usage, O(1) `hasChildren` checks, lazy regular expression generation, and removal of redundant processes:

| Route                                   | Node.js   | Deno      | Bun       |
| --------------------------------------- | --------- | --------- | --------- |
| short static `GET /user`                | 1.70x     | 1.40x     | 1.34x     |
| dynamic `GET /user/lookup/username/hey` | 1.38x     | 1.69x     | 1.51x     |
| wildcard `GET /static/index.html`       | 1.51x     | 1.72x     | 1.43x     |
| **all together**                        | **1.58x** | **1.60x** | **1.82x** |

Thanks @EdamAme-x!

### Fast Path for `c.json()`

`c.json()` now has the same fast path optimization as `c.text()`. When no custom status, headers, or finalized state exists, the Response is created directly without allocating a `Headers` object:

```ts
// This common pattern is now faster
return c.json({ message: 'Hello' })
```

Benchmark results:

| Metric     | Before    | After     | Change     |
| ---------- | --------- | --------- | ---------- |
| Reqs/sec   | 92,268    | 95,244    | **+3.2%**  |
| Latency    | 5.42ms    | 5.25ms    | **-3.1%**  |
| Throughput | 17.24MB/s | 19.07MB/s | **+10.6%** |

Thanks @mgcrea!

## New features

- feat(client): Add `ApplyGlobalResponse` type helper for RPC Client https://github.com/honojs/hono/pull/4556
- feat(ssg): add redirect plugin https://github.com/honojs/hono/pull/4599
- feat(client): $path https://github.com/honojs/hono/pull/4636
- feat(basic-auth): add context key and callback options https://github.com/honojs/hono/pull/4645
- feat(adapter): add getConnInfo for AWS Lambda, Cloudflare Pages, and Netlify https://github.com/honojs/hono/pull/4649
- feat(trailing-slash): add `alwaysRedirect` option to support wildcard routes https://github.com/honojs/hono/pull/4658
- feat(language): add progressive locale code truncation to normalizeLanguage https://github.com/honojs/hono/pull/4717
- feat(types): Add exports field to ExecutionContext https://github.com/honojs/hono/pull/4719

## Performance

- perf(context): add fast path to c.json() matching c.text() optimization https://github.com/honojs/hono/pull/4707
- perf(trie-router): improve performance (1.5x ~ 2.0x) https://github.com/honojs/hono/pull/4724
- perf(context): use `createResponseInstance` for new Response https://github.com/honojs/hono/pull/4733

## All changes

- fix(jsx/dom): handle empty arrays in render children loop by @mixelburg in https://github.com/honojs/hono/pull/4729
- perf(jsx/dom): flatten children once at the start to avoid repeated flattening by @usualoma in https://github.com/honojs/hono/pull/4730
- fix(client): skip undefined values in form data serialization by @aidenlx in https://github.com/honojs/hono/pull/4732
- feat(client): Add `ApplyGlobalResponse` type helper for RPC Client by @mohankumarelec in https://github.com/honojs/hono/pull/4556
- feat(ssg): add redirect plugin by @3w36zj6 in https://github.com/honojs/hono/pull/4599
- feat(client): $path by @ShaMan123 in https://github.com/honojs/hono/pull/4636
- feat(basic-auth): add context key and callback options by @AprilNEA in https://github.com/honojs/hono/pull/4645
- feat(adapter): add getConnInfo for AWS Lambda, Cloudflare Pages, and Netlify by @rokasta12 in https://github.com/honojs/hono/pull/4649
- feat(trailing-slash): add `alwaysRedirect` option to support wildcard routes by @yusukebe in https://github.com/honojs/hono/pull/4658
- perf(context): add fast path to c.json() matching c.text() optimization by @mgcrea in https://github.com/honojs/hono/pull/4707
- feat(language): add progressive locale code truncation to normalizeLanguage by @sorafujitani in https://github.com/honojs/hono/pull/4717
- feat(types): Add exports field to ExecutionContext by @toreis-up in https://github.com/honojs/hono/pull/4719
- perf(trie-router): improve performance (1.5x ~ 2.0x) by @EdamAme-x in https://github.com/honojs/hono/pull/4724
- perf(context): use `createResponseInstance` for new Response by @yusukebe in https://github.com/honojs/hono/pull/4733
- Next by @yusukebe in https://github.com/honojs/hono/pull/4735

## New Contributors

- @mixelburg made their first contribution in https://github.com/honojs/hono/pull/4729
- @aidenlx made their first contribution in https://github.com/honojs/hono/pull/4732
- @mohankumarelec made their first contribution in https://github.com/honojs/hono/pull/4556
- @ShaMan123 made their first contribution in https://github.com/honojs/hono/pull/4636
- @rokasta12 made their first contribution in https://github.com/honojs/hono/pull/4649
- @mgcrea made their first contribution in https://github.com/honojs/hono/pull/4707

**Full Changelog**: https://github.com/honojs/hono/compare/v4.11.10...v4.12.0