Next.jsのミドルウェアでHonoを使用する
CoeFont Tech Blog の記事は、Next.js の Middleware における複雑なロジック管理を解決するため、軽量フレームワークである Hono を組み合わせて利用する具体的な実装パターンとベストプラクティスを解説している。
キーポイント
Next.js Middleware の課題と Hono の導入動機
Next.js の Middleware は設定が単一で複雑なパス制御や認証ロジックの管理が大変になるため、軽量かつ高速な Hono を組み合わせて実装をシンプル化するアプローチが提案されている。
Web 標準 API を活用した基本連携
Next.js の Middleware シグネチャと Hono が Web 標準 API に基づいて動作している点を利用し、`app.fetch(req)` で両者を直接接続する基本的な実装コードが示されている。
AppRouter との連携における NextResponse.next() の重要性
Hono 側で処理を行っても Next.js の AppRouter にページを渡すには、`NextResponse.next()` を適切に返す必要があるという重要な実装ポイントが解説されている。
Cookie 設定とリクエストの再返却
Hono の Middleware で Cookie(例:LOCALE)を設定した場合、その値を Next.js に反映させるために、`NextResponse.next({ request: req })` を使用してリクエストオブジェクトを再返却する必要がある。
hono/vercel を使用した実装の簡略化
従来の手動記述から `handle(app)` を使うことで、Next.js Middleware での Hono の導入が容易になりました。
Web 標準 API に基づく互換性
Hono が Web 標準 API を採用しているため、Next.js の Middleware 環境でも基本的な動作はそのまま利用可能です。
影響分析・編集コメントを表示
影響分析
この記事は、Next.js エコシステムにおいて、フレームワーク固有の制限を外部の軽量ライブラリで補完する実践的なアーキテクチャパターンを示しており、大規模アプリケーションの開発現場における Middleware の設計指針として即座に活用できる価値があります。特に Cookie や国際化(i18n)処理など、複雑なロジックを分離・管理したい開発者にとって有益な解決策を提供しています。
編集コメント
Next.js の Middleware 機能は強力ですが、複雑な要件に対応する際にフレームワークの制約に直面することがあります。このように既存の軽量ツールを組み合わせることで、開発者の負担を減らしつつ柔軟性を高める手法は非常に示唆に富んでいます。
Next.js の Middleware で Hono を使う
Next.js
Hono tech株式会社 CoeFont でフロントエンドエンジニアをしている uzimaru です。 Next.js の Middleware で Hono を使ってみたのでそれについて記事にまとめます。
Next.js の Middleware はアプリケーションに1つだけしか設定出来ず、どの path で実行するかの設定も config で行います。
シンプルな実装のみなら良いのですが、path によってログインしているか確認したい、いくつかの処理を Middleware で適応したい、というように要件が複雑になると管理が大変になっていくと思います。
そこで、Hono のようなシンプルなフレームワークを Middleware で動かして実装をシンプルにしようというのがモチベーションです。
Hono - [炎] means flame🔥 in Japanese - is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js.
Honoは様々なランタイムで動作するWebフレームワークです。 より詳しくは、作者様の書いたこちらの記事を参照してください。
Middleware で Hono を動かしてみる
この Hono ですが Web標準API のみを利用して動いています。 また、Next.js の Middleware が受け取るシグネチャを見ると
type NextMiddleware = ( request: NextRequest, event: NextFetchEvent ) => NextMiddlewareResult | Promise<NextMiddlewareResult>;
という形になっています。 この NextRequest は Web標準の Request を拡張したものです。
NextMiddlewareResult は
export type NextMiddlewareResult = NextResponse | Response | null | undefined | void;
という型になっています。こちらもWeb標準ですね。
そのため、普通に Hono を使うだけでも十分動くということが分かったと思います。 最低限のコードは以下のようになります
import { Hono } from 'hono' import { NextRequest } from 'next/server' const app = new Hono() app.all('*', (ctx) => { return ctx.body(null) }) export const middleware = (req: NextRequest) => { return app.fetch(req) }
ただし、このコードでは想定している挙動はしてくれません。 見て分かるように、app.all で返している ctx.body(null) は null のボディを持つ Response を返してしまいます。
Middleware で Hono を使う
このままだとまともに使えないので使えるようにします。
NextResponse のドキュメントを見ると、AppRouterに処理を返すには NextResponse.next を返せば良いことが分かります。
import { Hono } from 'hono' import { NextRequest } from 'next/server' const app = new Hono() app.all('*', (ctx) => { return NextResponse.next() }) export const middleware = (req: NextRequest) => { return app.fetch(req) }
これで AppRouter に実装したページが表示されます。
処理を Middleware でまとめる
Middleware で実現した処理を Hono の Middleware として実装してまとめます。ちょっとややこしいですね。
今回は例として accept-language ヘッダーから言語を取得して cookie に保存する処理を実装してみます。
import { MiddlewareHandler } from 'hono' import { getCookie } from 'hono/cookie' import { NextRequest } from 'next/server' const i18nMiddleware: MiddlewareHandler = async (ctx, next) => { let locale = ctx.req.header('accept-language')?.split(',')[0]?.split('-')[0] if (locale !== 'en') { locale = 'ja' } if (!getCookie(ctx, 'LOCALE')) { const req = ctx.req.raw as NextRequest req.cookies.set('LOCALE', locale) } return next() }
書き方は一般的な Hono の Middleware と同じですが、いくつかポイントがあります。
Hono では ctx.req は HonoRequest という独自の型になっています。 NextRequest にアクセスするには ctx.req.raw を NextRequest にキャストする必要があります。
cookie に付いてですが、取得に関しては hono/cookie の getCookie が使えますが、設定は NextRequest の cookies を直接操作する必要があります。
NextResponse.next() に request オプションを渡すことで、変更した request を次の処理に渡すことができます。
Hono の Middleware を設定する
作成した Hono の Middleware を設定します。 今回は全部の path に対して有効にしたいので以下のように書きます。
const app = new Hono() app.use(i18nMiddleware)
しかし、この状態だと LOCALE を cookie に設定した request が次の処理に渡りません。 そのため、最後に request を渡す処理を追加する必要があります。
app.all('*', ctx => { const req = ctx.req.raw as NextRequest return NextResponse.next({ request: req }) })
これで Middleware で設定した cookie が反映されるようになりました。
Middleware の定義部分について
export const middleware = (req: NextRequest) => { return app.fetch(req) }
のように書いていましたが、実は hono/vercel に Next.js の Middleware 用のヘルパーが用意されています。
import { handle } from 'hono/vercel' export const middleware = handle(app)
Hono が Web標準API を使った実装になってくれているおかげで Next.js の Middleware で簡単に使うことができました。 基本的にはそのまま使えるのですが、Response 周りや cookie 周りがやや特殊だったのでそこだけ気をつける必要がありそうです。
Hono を使って書き換えたおかげで Middleware の見通しが良くなったのが良かったです。 Next.js の Middleware の書きにくさを感じている人は是非試してみてください。
CoeFontPublicationAI音声プラットフォーム「CoeFont(コエフォント)」の公式テックブログです。

原文を表示
Next.js
Hono tech株式会社 CoeFont でフロントエンドエンジニアをしている uzimaru です。 Next.js の Middleware で Hono を使ってみたのでそれについて記事にまとめます。
Next.js の Middleware はアプリケーションに1つだけしか設定出来ず、どの path で実行するかの設定も config
シンプルな実装のみなら良いのですが、path によってログインしているか確認したい、いくつかの処理を Middleware で適応したい、というように要件が複雑になると管理が大変になっていくと思います。
そこで、Hono のようなシンプルなフレームワークを Middleware で動かして実装をシンプルにしようというのがモチベーションです。
Hono - [炎] means flame🔥 in Japanese - is a small, simple, and ultrafast web framework for the Edges. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js.
いろいろなランタイムで動く WebFramework です。 より詳しくは、作者様の書いたこちらの記事を参照してください。
Middleware で Hono を動かしてみる
この Hono ですが Web標準API のみを利用して動いています。 また、Next.js の Middleware が受け取るシグネチャを見ると
type NextMiddleware = ( request: NextRequest, event: NextFetchEvent ) => NextMiddlewareResult | Promise<NextMiddlewareResult>;
という形になっています。 この NextRequest
NextMiddlewareResult
export type NextMiddlewareResult = NextResponse | Response | null | undefined | void;
という型になっています。こちらもWeb標準ですね。
そのため、普通に Hono を使うだけでも十分動くということが分かったと思います。 最低限のコードは以下のようになります
import { Hono } from 'hono' import { NextRequest } from 'next/server' const app = new Hono() app.all('*', (ctx) => { return ctx.body(null) }) export const middleware = (req: NextRequest) => { return app.fetch(req) }
ただし、このコードでは想定している挙動はしてくれません。 見て分かるように、app.all
Middleware で Hono を使う
このままだとまともに使えないので使えるようにします。
NextResponse のドキュメントを見ると、AppRouterに処理を返すには NextResponse.next
import { Hono } from 'hono' import { NextRequest } from 'next/server' const app = new Hono() app.all('*', (ctx) => { return NextResponse.next() }) export const middleware = (req: NextRequest) => { return app.fetch(req) }
これで AppRouter に実装したページが表示されます。
処理を Middleware でまとめる
Middleware で実現した処理を Hono の Middleware として実装してまとめます。ちょっとややこしいですね。
今回は例として accept-language
import { MiddlewareHandler } from 'hono' import { getCookie } from 'hono/cookie' import { NextRequest } from 'next/server' const i18nMiddleware: MiddlewareHandler = async (ctx, next) => { let locale = ctx.req.header('accept-language')?.split(',')[0]?.split('-')[0] if (locale !== 'en') { locale = 'ja' } if (!getCookie(ctx, 'LOCALE')) { const req = ctx.req.raw as NextRequest req.cookies.set('LOCALE', locale) } return next() }
書き方は一般的な Hono の Middleware と同じですが、いくつかポイントがあります。
Hono では ctx.req
cookie に付いてですが、取得に関しては hono/cookie
NextResponse.next()
Hono の Middleware を設定する
作成した Hono の Middleware を設定します。 今回は全部の path に対して有効にしたいので以下のように書きます。
const app = new Hono() app.use(i18nMiddleware)
しかし、この状態だと LOCALE
app.all('*', ctx => { const req = ctx.req.raw as NextRequest return NextResponse.next({ request: req }) })
これで Middleware で設定した cookie が反映されるようになりました。
Middleware の定義部分について
export const middleware = (req: NextRequest) => { return app.fetch(req) }
のように書いていましたが、実は hono/vercel
import { handle } from 'hono/vercel' export const middleware = handle(app)
Hono が Web標準API を使った実装になってくれているおかげで Next.js の Middleware で簡単に使うことができました。 基本的にはそのまま使えるのですが、Response 周りや cookie 周りがやや特殊だったのでそこだけ気をつける必要がありそうです。
Hono を使って書き換えたおかげで Middleware の見通しが良くなったのが良かったです。 Next.js の Middleware の書きにくさを感じている人は是非試してみてください。
CoeFontPublicationAI音声プラットフォーム「CoeFont(コエフォント)」の公式テックブログです。

関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み