Hono RPCモード完全ガイド — コード生成不要で実現する型安全フルスタック開発【2026年版】
HonoのRPCモードを使えばOpenAPIやコード生成なしでtRPC同等の型安全フルスタック開発が実現できます。hcクライアント、InferRequestType、複数ルート統合まで網羅した2026年版完全ガイド。
Hono RPCモードとは何か?
Hono RPCモードはサーバーで定義したルートの型情報をクライアント側で自動推論できる仕組みです。OpenAPIスペックもコード生成も不要で、tRPCに近い体験をHonoネイティブに実現できます。`export type AppType = typeof route` の1行でサーバーとクライアントが型でつながります。
RPCモードの仕組みを理解する
上図のように、サーバーの `AppType` がそのまま `hc<AppType>` クライアントに渡されます。ビルド時に型が検証され、ランタイムエラーを未然に防ぎます。
tRPC・OpenAPI・GraphQLとの違い
下表で主要な型安全API手法を比較します。
| 比較項目 | Hono RPC | tRPC | OpenAPI | GraphQL |
|---|---|---|---|---|
| コード生成 | 不要 | 不要 | 必要 | 必要 |
| スキーマ定義 | Zod (任意) | Zod/Yup | YAML/JSON | SDL |
| フレームワーク依存 | Hono専用 | framework非依存 | 非依存 | 非依存 |
| バンドルサイズ | 最小 | 中 | 大 | 大 |
| Edge対応 | ネイティブ | 限定的 | 非依存 | 非依存 |
| 学習コスト | 低 | 低〜中 | 中 | 高 |
サーバー側の基本実装
Honoサーバーでルートを定義し、型をエクスポートするだけです。`zValidator` でリクエストボディを型安全にバリデーションできます。
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod'
const app = new Hono()
const route = app.post(
'/posts',
zValidator('json', z.object({
title: z.string().min(1),
body: z.string()
})),
(c) => {
const data = c.req.valid('json')
return c.json({ ok: true, id: 1, ...data }, 201)
}
)
export type AppType = typeof route
export default appクライアント側の実装
`hc` 関数に `AppType` を渡すだけで、メソッド名・引数・戻り値すべてが型推論されます。IDEの補完も完全に機能します。
import type { AppType } from './server'
import { hc } from 'hono/client'
const client = hc<AppType>('http://localhost:8787/')
const res = await client.posts.$post({
json: { title: 'Hello', body: 'Hono RPC is great!' }
})
if (res.ok) {
const data = await res.json()
// data: { ok: true, id: number, title: string, body: string }
}InferRequestType / InferResponseType の活用
`InferRequestType` と `InferResponseType` を使えば、クライアントコードで型を明示的に取り出せます。フォームバリデーションや型ガードに役立ちます。
import { InferRequestType, InferResponseType } from 'hono/client'
import type { AppType } from './server'
import { hc } from 'hono/client'
const client = hc<AppType>('/')
type CreatePostInput = InferRequestType<typeof client.posts.$post>['json']
// => { title: string; body: string }
type CreatePostOutput = InferResponseType<typeof client.posts.$post, 201>
// => { ok: boolean; id: number; title: string; body: string }$url() / $path() ユーティリティ
`$url()` はURLオブジェクトを、`$path()` はパス文字列を返します。ハードコードされたURL文字列を排除し、リファクタリング時のミスを防ぎます。
const url = client.posts.$url()
// => URL { href: 'http://localhost:8787/posts' }
const path = client.posts.$path()
// => '/posts'
// パスパラメータがある場合
const postUrl = client.posts[':id'].$url({ param: { id: '42' } })
// => URL { href: 'http://localhost:8787/posts/42' }複数ルートの統合 — モジュラーなRPC API設計
大規模アプリでは機能ごとにルートを分割し、メインアプリに統合します。`AppType` は全ルートを含む型になります。
// routes/posts.ts
const postsRoute = new Hono()
.get('/', (c) => c.json({ posts: [] }))
.post('/', zValidator('json', postSchema), (c) => {
return c.json({ ok: true }, 201)
})
export type PostsType = typeof postsRoute
// routes/users.ts
const usersRoute = new Hono()
.get('/:id', (c) => c.json({ user: { id: c.req.param('id') } }))
export type UsersType = typeof usersRoute
// app.ts
const app = new Hono()
.route('/posts', postsRoute)
.route('/users', usersRoute)
export type AppType = typeof app
export default appNext.js / React との統合パターン
Next.js App Router では `hc` クライアントをシングルトンとして管理すると、型推論が安定します。Server ComponentsとClient Componentsの両方で利用できます。
// lib/client.ts (Next.js)
import { hc } from 'hono/client'
import type { AppType } from '@/server/app'
export const client = hc<AppType>(process.env.NEXT_PUBLIC_API_URL!)
// app/posts/page.tsx (Server Component)
import { client } from '@/lib/client'
export default async function PostsPage() {
const res = await client.posts.$get()
const { posts } = await res.json()
return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>
}エラーハンドリング
Honoでは `HTTPException` を使った一貫したエラーハンドリングが推奨されます。RPC経由でもエラーレスポンスは型推論されます。
import { HTTPException } from 'hono/http-exception'
const route = app
.get('/posts/:id', async (c) => {
const post = await db.find(c.req.param('id'))
if (!post) throw new HTTPException(404, { message: 'Not Found' })
return c.json({ post }, 200)
})
// グローバルエラーハンドラー
app.onError((err, c) => {
if (err instanceof HTTPException) {
return err.getResponse()
}
return c.json({ error: 'Internal Server Error' }, 500)
})型推論の制約と最適化
大規模APIではコンパイル時間が増加することがあります。以下の対策が有効です。
| 対策 | 効果 |
|---|---|
| ルートを機能単位でモジュール分割 | 型推論の範囲を限定 |
| `satisfies` 演算子を避ける | 型複雑度を低減 |
| `hc` クライアントをシングルトン化 | 再インスタンス化コストを排除 |
| TypeScript 5.5+ のインクリメンタルビルド | 差分ビルドで高速化 |
既存OpenAPIプロジェクトからの移行戦略
段階的移行が安全です。`@hono/swagger-ui` と `@hono/zod-openapi` を使えば、OpenAPIドキュメントを維持しながらHono RPCを並行導入できます。新規エンドポイントからRPCを採用し、旧エンドポイントを順次移行します。
FAQ
Q1. Hono RPCはtRPCの代替になりますか? A. ユースケースによります。tRPCはフレームワーク非依存でNext.jsとの統合が成熟しています。HonoはEdge環境やマルチランタイムを重視する場合に優れており、既存のHonoサーバーを使っているなら追加ライブラリ不要でRPC化できます。 Q2. hcクライアントはブラウザでも動作しますか? A. はい。`hono/client` はWeb Standards準拠のため、Node.js・Bun・Deno・ブラウザいずれでも動作します。 Q3. ファイルアップロードは型安全に扱えますか? A. `zValidator('form', ...)` を使いFormDataバリデーションをサーバー側で定義すれば、クライアントからも型推論されます。 Q4. WebSocketはRPCモードで使えますか? A. 現時点(2026年)でHono RPCはHTTPベースのリクエスト/レスポンスを対象としています。WebSocketにはHonoのネイティブWSサポートを別途使用してください。 Q5. Zodなしでも使えますか? A. はい。`zValidator` は任意です。バリデーションなしでルートを定義しても `AppType` エクスポートとhcクライアントは動作します。ただしリクエスト型推論の精度は下がります。 Q6. Cloudflare Workersでも動作しますか? A. 完全に対応しています。HonoはCloudflare Workers向けに最適化されており、RPCモードもEdge環境で問題なく動作します。 Q7. 複数のベースURLを持つマイクロサービスに対応できますか? A. 各サービスごとに個別の `hc<ServiceType>(baseUrl)` クライアントを作成します。型は独立して管理されるため、マイクロサービス構成でも型安全を維持できます。
Oflightへのご相談
HonoとRPCモードを活用した型安全フルスタック開発の導入支援、既存APIのHono移行、Cloudflare Workers対応など、弊社エンジニアがサポートします。初回相談は無料です。詳しくはソフトウェア開発サービスをご覧ください。
お気軽にご相談ください
お問い合わせ