株式会社オブライト
Software Dev2026-04-08

Hono RPCモード完全ガイド — コード生成不要で実現する型安全フルスタック開発【2026年版】

HonoのRPCモードを使えばOpenAPIやコード生成なしでtRPC同等の型安全フルスタック開発が実現できます。hcクライアント、InferRequestType、複数ルート統合まで網羅した2026年版完全ガイド。


Hono RPCモードとは何か?

Hono RPCモードはサーバーで定義したルートの型情報をクライアント側で自動推論できる仕組みです。OpenAPIスペックもコード生成も不要で、tRPCに近い体験をHonoネイティブに実現できます。`export type AppType = typeof route` の1行でサーバーとクライアントが型でつながります。

RPCモードの仕組みを理解する

Loading diagram...

上図のように、サーバーの `AppType` がそのまま `hc<AppType>` クライアントに渡されます。ビルド時に型が検証され、ランタイムエラーを未然に防ぎます。

tRPC・OpenAPI・GraphQLとの違い

下表で主要な型安全API手法を比較します。

比較項目Hono RPCtRPCOpenAPIGraphQL
コード生成不要不要必要必要
スキーマ定義Zod (任意)Zod/YupYAML/JSONSDL
フレームワーク依存Hono専用framework非依存非依存非依存
バンドルサイズ最小
Edge対応ネイティブ限定的非依存非依存
学習コスト低〜中

サーバー側の基本実装

Honoサーバーでルートを定義し、型をエクスポートするだけです。`zValidator` でリクエストボディを型安全にバリデーションできます。

ts
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の補完も完全に機能します。

ts
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` を使えば、クライアントコードで型を明示的に取り出せます。フォームバリデーションや型ガードに役立ちます。

ts
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文字列を排除し、リファクタリング時のミスを防ぎます。

ts
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` は全ルートを含む型になります。

ts
// 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 app

Next.js / React との統合パターン

Next.js App Router では `hc` クライアントをシングルトンとして管理すると、型推論が安定します。Server ComponentsとClient Componentsの両方で利用できます。

ts
// 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経由でもエラーレスポンスは型推論されます。

ts
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対応など、弊社エンジニアがサポートします。初回相談は無料です。詳しくはソフトウェア開発サービスをご覧ください。

お気軽にご相談ください

お問い合わせ