プログラミング フレームワーク ソフトウェア 公開日 2026.05.15 更新日 2026.05.20

tRPC とは何か?TypeScript で型安全な API を作る仕組みと REST / GraphQL との使い分け

tRPC は TypeScript で 「スキーマ生成も OpenAPI もなしで、サーバとクライアントが完全に型共有する API」を作るためのライブラリです。Zod での入力検証、React Query との統合、Next.js / モノレポでの典型構成、REST / GraphQL との使い分けまで、「なぜ流行ったのか」 を実務目線で整理します。

先に要点

  • tRPCTypeScript 用の 型安全な API ライブラリ。サーバが定義した型を クライアント側で直接インポート できるため、「OpenAPI / GraphQL スキーマを生成して同期する」 ような工程が不要。
  • API 呼び出しは client.user.byId.query({ id: 1 }) のように 「関数を呼ぶ感覚」 で書ける。レスポンスの型も自動で導出されるので、「API レスポンスの型を別に書く」 作業がゼロになる。
  • Zod による入力検証、pnpm workspaces によるモノレポ、Vercel へのデプロイ、というモダン TS スタックの中心に位置するライブラリ。
  • 万能ではない。「 外部に公開する API」 「非 TypeScript クライアント」 が前提なら REST / GraphQL の方が向く。tRPC は基本 「サーバとクライアントを両方自社の TS で書く案件」 に最適化されている。

tRPC ってよく聞くけど、結局 REST と何が違うの? GraphQL でいいのでは? 「モノレポなら使うべき?」 ── TypeScript フルスタックで開発する案件が増えるほど、tRPC の名前は外せない存在になってきました。

ざっくり言うと、tRPC は サーバが書いた TypeScript 型を、クライアントから直接 import して呼び出せる ことを最大の売りにした API ライブラリです。 OpenAPI のスキーマ定義や GraphQL の SDL を介さず、TypeScript の型システムをそのまま API 契約として使う という割り切りで、「型を書く時間 = API 契約を書く時間」 という体験を実現します。

この記事では、2026年5月時点の tRPC を、「何を解決するのか・REST / GraphQL との違い・どう書くのか・どこで効くか・どこでは向かないか」 の順で整理します。

tRPC が解決した問題

「なぜ tRPC が広まったか」 は、フロントエンドエンジニアが 「API 開発のたびに同じ作業をしている」 という不満の歴史を見ると分かります。

①型を二重に書く

サーバで 「User」 型を書き、フロントでも 「ApiUser」 型を書く。「OpenAPI を生成してジェネレータを回す」 という選択肢もあるが、ビルドの一手間と微妙にずれる型が問題になる。

エンドポイントの構造を覚える必要がある

GET /api/users/:id」 を覚え、「fetch」 で叩き、JSON をパースし、型を当てる ─ という同じ作業を毎回書く。「シンプルだが面倒」 が積み重なる。

③ スキーマと実装がずれる

OpenAPI / GraphQL の SDL を更新し忘れると、フロントとバックの認識がずれる。API ドキュメントは古くなる 問題が構造的に発生。

TypeScript の表現力を使い切れない

OpenAPI / GraphQL は TS より表現力が低い。「ユニオン型」 「条件付き型」 などの強い型情報が、API 境界で失われがち。

tRPC は サーバとクライアントが同じリポジトリ(or モノレポ)にあるなら、TS 型をそのまま共有すればいいじゃないか という、ある意味で開き直った発想で、これらの問題を一気に解消しました。

基本の使い方 — 「Procedure」 と 「Router」

最小例で雰囲気を確認します。

// server/router.ts
import { initTRPC } from '@trpc/server';
import { z } from 'zod';

const t = initTRPC.create();

export const appRouter = t.router({
  user: t.router({
    byId: t.procedure
      .input(z.object({ id: z.string() }))
      .query(async ({ input }) => {
        return await db.user.findUnique({ where: { id: input.id } });
      }),
    create: t.procedure
      .input(z.object({ name: z.string(), email: z.string().email() }))
      .mutation(async ({ input }) => {
        return await db.user.create({ data: input });
      }),
  }),
});

export type AppRouter = typeof appRouter;

クライアント側はこうなります。

// client.ts
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '../server/router';

const trpc = createTRPCProxyClient<AppRouter>({
  links: [httpBatchLink({ url: '/trpc' })],
});

const user = await trpc.user.byId.query({ id: '42' });
const created = await trpc.user.create.mutate({ name: 'Alice', email: 'a@example.com' });

ポイント:

  • サーバの 「AppRouter」 型を クライアントが 「import type」 するだけ で、利用できるエンドポイント、引数、戻り値の型が完全に揃う。
  • 「query」 は GET 系の参照、「mutation」 は POST/PUT/DELETE 系の更新、と概念的に分ける。
  • 入力検証は Zod をそのまま使う(Yup / Valibot 等もアダプタ経由で可)。

「スキーマ生成のコマンドを叩く必要がない」 のが、地味だが体験を大きく変える点です。

REST / GraphQL との比較

3つを並べると、それぞれの立ち位置が見えやすくなります。

REST GraphQL tRPC
API 契約の形 OpenAPI(別途定義) SDL(別途定義) TypeScript の型(自動)
クライアントの呼び方 HTTP リクエスト クエリ文字列 + 変数 関数呼び出し
型生成 codegen が必要 codegen が必要 不要(import するだけ)
外部公開向き ◎(標準) ○(SDL があれば多言語OK) ×(TS 前提)
クライアントの言語 何でもOK 何でもOK TypeScript のみ
サーバ↔フロントが同じ TS 普通 普通 圧倒的に楽
クエリの柔軟性 低(エンドポイント固定) 高(クライアントが選ぶ) 中(サーバが procedure を提供)
ツール / ドキュメント 豊富 豊富 TS スタック向きに豊富

要点は 「 API を誰が・何で呼ぶか」 で選ぶ:

  • 外部に公開、複数言語クライアント → REST
  • 大規模、複雑なクエリ要件、複数チーム → GraphQL
  • 内製、サーバもクライアントも TypeScript → tRPC

「どれが優れているか」 ではなく、「案件の境界条件にどれが合うか」 で決める道具立てです。

React Query との統合

tRPC が普段使いで快適に感じるもう1つの理由が、React Query(TanStack Query)との深い統合 です。

// 通常版 React Query を意識せずに使える
const { data, isLoading, error } = trpc.user.byId.useQuery({ id: '42' });

const create = trpc.user.create.useMutation({
  onSuccess: () => {
    trpc.user.byId.invalidate({ id: '42' });
  },
});

「fetch を直接書く / axios を呼ぶ」 が、「React Query のフック + 型安全な引数 + 自動キャッシュ無効化」 に置き換わります。 キャッシュ、リトライ、optimistic update など React Query の機能はそのまま使え、「データ取得の標準的なコードベース」 が一気に手に入る、というのが現場の体感です。

どこで効くか — tRPC が活きる案件

実務で 「tRPC を選んでよかった」 となる構成は、おおむね決まっています。

Next.js + 自社 TypeScript フルスタック

Next.js の App Router / Pages Router の API レイヤを tRPC で組む構成は最頻出。「サーバ側のコードを書く感覚で API が完成」 する。

② モノレポでサーバとクライアントを並走

pnpm workspaces や Turborepo で 「apps/web」 と 「apps/api」 を並べる構成と相性◎。「同じ型を共有」 が物理ファイルとして自然に成立する。

③ 小〜中規模スタートアップ

「 早く作って・早く出す」 が求められるフェーズで、「API スキーマの整備」 を後回しにしても型安全を保てる。MVP〜スケール初期で抜群に効く。

④ 社内ツール / 管理画面

外部 API としての公開が不要で、TS で書く社内システムなら、tRPC で書かない理由がほぼない。

「完全に内向きの TS スタック」 のときに、tRPC は最も大きな威力を発揮します。 逆に 「 外向きの API として公開する」 場合は、後述のように tRPC ではなく REST / GraphQL の方が自然 です。

どこでは向かないか — tRPC の限界

「流行っているから tRPC」 で選ぶと、後で痛い目を見る場面もあります。

①外部公開 API

API ドキュメントを世間に公開して、サードパーティが叩く前提の API は、tRPC では難しい。「REST + OpenAPI」 のほうが標準化されており、SDK 配布も楽。

② モバイルや別言語クライアント

iOS / Android / Go / Rust など TypeScript 以外のクライアントを想定する場合、tRPC は使えない / 旨味がない。「type を import する」 が成立しないため。

③ 巨大なフロントチーム × 専任バックエンド

フロントとバックが完全に別の組織 / 別の技術スタック」 だと、tRPC の 「型共有」 のメリットが失われる。GraphQL / REST + 明示的なスキーマの方が運用しやすい。

④ 非常に複雑なクエリ要件

「 1画面で 30 種類のデータを取得し、フィルタや並びをクライアント側で柔軟に選ぶ」 のような GraphQL の本来の強みが効く案件は、GraphQL のほうが向く。

「内向き TS なら tRPC、外向きや複雑な要件なら別」 という判断軸を持っておくと、選定で迷いが減ります。

認証・認可・ミドルウェア

tRPC は procedure ミドルウェア という仕組みで、認証・認可・ロギング・レート制御などを共通化できます。

const isAuthed = t.middleware(async ({ ctx, next }) => {
  if (!ctx.user) throw new Error('UNAUTHORIZED');
  return next({ ctx: { ...ctx, user: ctx.user } });
});

export const protectedProcedure = t.procedure.use(isAuthed);

// 使うとき
export const appRouter = t.router({
  me: protectedProcedure.query(({ ctx }) => ctx.user),
});

「保護したい procedure は protectedProcedure を使う」 と決めるだけで、認証チェックが一律にかかる、という設計です。 HTTP ステータスコードの記事 で触れた 「401 / 403 を返す境界」 を、tRPC では `エラーコード(「UNAUTHORIZED」 「FORBIDDEN」)」 として表現できる仕組みも持っています。

モノレポでの典型構成

tRPC が真価を発揮するのは、モノレポでの構成です。

読み込み中...

「API の追加 = サーバの router にメソッドを増やす」 だけで、クライアント側は即座に補完が効く ─ という体験が、現代の TS フルスタックにおける tRPC の魅力の核心です。

AI 時代の tRPC 観

AI を組み込んだ TS アプリでも、tRPC の役割は重要になっています。

AI 呼び出しの型安全

「 AI に何を投げて、何が返ってくるか」 を Zod スキーマで宣言し、tRPC の procedure として公開する。フロントから 「trpc.ai.summarize.useMutation」 のような自然な呼び出しが可能になる。

ストリーミングと相性

「 tRPC + React Query の streaming」 で、「AI が応答を生成する過程」 を UI にリアルタイム反映するのが楽。LLM のストリーミング応答に向いた構成。

プロトタイピングの速さ

AI で UI を作る([v0 / Vercel](/articles/what-is-v0-vercel-ai-ui-generator-usage))と、その UI が叩く API を tRPC で爆速に書ける、というコンビは MVP の速度を一段押し上げる。

フルスタック TS の重要性

AI 時代に「JS / TS 1 言語でフロントとバックを書く」価値が更に上がる。tRPC は その重要性に最も乗っているライブラリと言っても言い過ぎではない。

「小さなチームが AI で爆速に開発する」 文脈で、tRPC は事実上のスタンダードのひとつになっています。 「内向き / TypeScript / モノレポ」 が揃った瞬間に、tRPC の合理性は最大化される、というのが2026年現在の景色です。

tRPC に関するよくある質問

Q. tRPC は本番運用に耐えますか?

A. 十分耐えています。Vercel・Cal.com・PlanetScale など多くの著名プロダクトで本番採用実績があり、「v10」 以降は安定して使われています。設計が割り切られているがゆえに、ライブラリとしての複雑性は小さく、運用上のトラブルは少なめというのが現場の評価です。

Q. REST / GraphQL を捨てて全部 tRPC にすべきですか?

A. いいえ。内向きは tRPC、外向き API は REST / GraphQL の使い分けが現実的です。同じ会社の中で、「社内ツールは tRPC、公開 API は REST」 という二刀流の構成も普通にあります。

Q. Zod は必須ですか?

A. 必須ではないですが、「事実上の標準コンビ」 です。Zod を使うと 「 入力検証 + 型推論 + tRPC procedure の型」 が全部1つの定義で済む ので、これを採用しないのはむしろ手間が増えやすいです。Valibot などのアダプタも存在します。

Q. SSR / Next.js での扱いはどうなりますか?

A. tRPC は Next.js を一級サポート しています。「@trpc/next」 で SSR / SSG / RSC との統合を提供し、「サーバコンポーネントから直接 procedure を呼ぶ」 ような構成も可能です。Next.js + tRPC は現在の TS フルスタック開発で頻出するセットです。

Q. パフォーマンスは REST より劣りますか?

A. 大差ありません。HTTP の上で動く JSON 通信 という意味では REST と同等のオーバーヘッドで、`バッチング(「httpBatchLink」)」 で複数 procedure をまとめて送ることで、むしろ通信回数を減らせる場面もあります。

Q. tRPC の学習コストはどのくらい?

A. TypeScript と Zod を知っていれば、半日〜1日で書き始められる 程度です。「procedure / router / client / React Query」 の4語と、「query / mutation / input / output」 の4語を押さえれば、最初のエンドポイントは作れます。

Q. tRPC を採用すると、技術ロックインは厳しいですか?

A. ある程度はあります。「tRPC で書いた procedure を REST にエクスポート」 するアダプタもありますが、設計の根っこは TS の型共有前提なので、「完全に別技術に移行する」 ときは書き直しに近い作業が発生します。これも 「内向きの内製案件で使う」 という前提なら問題になりにくい、というのが多くの判断です。

参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。