SPAを作るたびにAPIエンドポイントを量産していませんか。@hono/inertiaを使えば、ルート定義だけでReact・Vue・Svelteのページを返せます。API層もクライアントサイドルーターも必要ありません。
この記事でわかること:
- @hono/inertiaが解決する課題とInertia.jsの基本的な仕組み
- React・Vue・Svelteで使うための導入手順
- TypeScriptの型安全を活かしたページ定義の方法
- Next.jsやRemixとのアプローチの違い
Inertia.jsとは何か
Inertia.jsは、サーバーサイドのルートからフロントエンドのコンポーネントへ直接データを渡すアダプターです。もともとはLaravelコミュニティで広まった技術で、「SPAのUXをAPIなしで実現する」というコンセプトを持っています。
通常のSPA開発では、サーバー側にREST APIやGraphQLのエンドポイントを用意し、クライアント側でデータフェッチとルーティングを実装します。Inertia.jsはこの二重構造を取り除きます。サーバーがHTMLの代わりにJSONページオブジェクトを返し、クライアント側のInertiaアダプターがそれを受け取ってコンポーネントをレンダリングします。初回アクセスではSSRされたHTMLを返し、以降のページ遷移ではJSONだけをやり取りする仕組みです。
@hono/inertiaの概要
@hono/inertiaは、WebフレームワークHonoの公式ミドルウェアとしてリリースされたInertia.jsアダプターです。2026年4月28日にHonoの作者であるYusuke Wada氏が公開を発表しました。バージョンは0.2.0で、npmパッケージ名は@hono/inertiaです。
Hono本体はGitHubスター数30,000超、Web標準API(Web Standards)の上に構築された軽量フレームワークとして知られています。Cloudflare Workers、Bun、Node.js、Denoなど複数のランタイムで動作します。このHonoにInertia.jsプロトコルの完全対応を加えたのが@hono/inertiaです。
何が解決されるのか
フルスタックのWebアプリを作る場合、従来は以下の構成が一般的でした。
サーバー側でAPIエンドポイントを定義し、クライアント側でReact RouterやVue Routerを設定し、fetchやaxiosでデータを取得します。ルートが増えるたびにAPI側とクライアント側の両方にコードが必要になり、型の整合性を保つのも手間がかかります。
@hono/inertiaでは、サーバーのルート定義だけで完結します。
app.use(inertia())
app.get('/posts/:id', (c) => c.render('Posts/Show', { post }))
この2行で、/posts/:idへのアクセス時にReact(またはVue・Svelte)のPosts/Showコンポーネントがpostをpropsとして受け取ります。REST APIを別途用意する必要はありません。
主な機能
Inertiaプロトコル完全対応: 初回ロードではハイドレーション可能なHTMLを返し、SPA内のナビゲーションではJSONページオブジェクトを返します。アセットバージョンが古い場合は409レスポンスでフルリロードを促します。
3つのフレームワーク対応: React、Vue、Svelteのいずれでもページコンポーネントを書けます。フレームワークの選択はクライアント側のセットアップで決まり、サーバー側のコードは共通です。
TypeScript型安全: 付属のViteプラグインinertiaPages()がpages.gen.tsを自動生成します。c.render()の第1引数にはディスク上に実在するページ名だけが許可され、タイポはコンパイルエラーになります。
c.render('About', { title: 'About' }) // OK
c.render('Hme', { message: 'oops' }) // コンパイルエラー
JSON APIの自動提供: application/jsonを受け付けるリクエストに対しては、同じルートがJSON形式でpropsを返します。SPAのページとAPIレスポンスを1つのルートで兼ねられます。
マルチランタイム対応: Honoがサポートするすべてのランタイムでそのまま動きます。Cloudflare Workers、Node.js、Bun、Denoのいずれでもデプロイ可能です。
導入手順
npmでインストールします。
npm i @hono/inertia
サーバー側の基本構成はシンプルです。rootViewでHTMLシェルを定義し、ミドルウェアに渡します。
import { Hono } from 'hono'
import { inertia } from '@hono/inertia'
import { rootView } from './root-view'
const app = new Hono()
app.use(inertia({ version: '1', rootView }))
app.get('/', (c) => c.render('Home', { message: 'Hello' }))
app.get('/posts/:id', (c) => c.render('Posts/Show', { id: c.req.param('id') }))
クライアント側では、InertiaのReactアダプターでページコンポーネントを解決します。
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client'
createInertiaApp({
resolve: async (name) => {
const pages = import.meta.glob('../app/pages/**/*.tsx')
const page = await pages[`../app/pages/${name}.tsx`]()
return page.default
},
setup({ el, App, props }) {
createRoot(el).render(<App {...props} />)
},
})
Cloudflare Workers + Vite構成の完全なサンプルはyusukebe/hono-inertia-exampleで公開されています。
Next.js・Remixとの違い
Next.jsやRemixもフルスタックフレームワークとしてサーバーとクライアントを統合しています。ただし、アプローチが異なります。
Next.jsはServer ComponentsとApp Routerによるファイルベースルーティングを採用し、React Server Components(RSC)プロトコルで差分更新します。Remixはローダーとアクションという仕組みでサーバーとクライアントを橋渡しします。いずれもReact専用で、独自のルーティング規約に従う必要があります。
Hono + Inertia.jsは、サーバー側のルーティングにHonoの自由度を維持したまま、フロントエンドのフレームワーク選択もReact・Vue・Svelteから選べます。ランタイムの制約もありません。「軽量なサーバーフレームワーク+好きなUIライブラリ」という組み合わせを維持しつつ、SPAのUXを実現する選択肢です。
一方、現時点ではExperimentalの扱いであり、Next.jsのような画像最適化やISR(Incremental Static Regeneration:増分的な静的再生成)といった付随機能は含みません。シンプルさを重視する構成です。
まとめ
Inertia.jsはLaravelの世界で成熟した技術ですが、Hono公式ミドルウェアとして登場したことで、エッジランタイムやマルチフレームワーク環境でも使えるようになりました。Experimentalではあるものの、Viteプラグインによる型生成やJSON API自動提供など、実用的な機能が揃っています。Next.jsやRemixの規約が重いと感じているプロジェクトでは、試してみる価値があります。
