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の規約が重いと感じているプロジェクトでは、試してみる価値があります。