Next.js Server Actions と tRPC を組み合わせるメリット
Next.js Server Actionsは、Next.js 13で導入された機能で、クライアントから直接サーバー上の関数を呼び出すRPC(リモートプロシージャコール)の仕組みです。クライアントコンポーネントからまるで通常の関数のようにサーバー関数を呼び出せ、ネットワーク通信の詳細はフレームワークが抽象化してくれます (Using Server Actions with tRPC | tRPC)。 一方tRPCは、エンドツーエンドで型安全なAPIを構築するフレームワークで、サーバー側にTypeScriptで関数(プロシージャ)を定義するとクライアント側からコンパイル時チェック付きで呼び出すことができます。
両者を組み合わせることで、以下のメリットが得られます。
-
フロント~バックエンド間の完全な型安全性: Server Actionsも関数シグネチャで型定義できますが、tRPCを使うとサーバー・クライアント双方で同じ型定義を共有し、フルスタックで型の整合性が保証されます (Using Server Actions with tRPC | tRPC) フロントエンドからサーバー関数を呼び出す際に型が自動補完され、コンパイル時に不整合が検出できるため、バグを減らせます。
-
入力バリデーションとセキュリティの強化: Server Actions自体はシンプルな仕組みで、入力検証や認可チェックなどは開発者が手動で実装する必要があります (Using Server Actions with tRPC | tRPC) tRPCはこれらをビルトインで提供しており、スキーマバリデーション(例えばZodによる入力チェック)、認証・認可用ミドルウェア、出力データの検証や変換などが容易に導入できます (Using Server Actions with tRPC | tRPC) そのため不正なリクエストや無効なデータからAPIを保護できます。実際、tRPCを組み合わせたServer Actionは未認証ユーザから保護され、SQLインジェクションのような攻撃に対する入力バリデーションも備えた形で簡潔に定義できます (Using Server Actions with tRPC | tRPC)
-
開発者体験(DX)の向上: Server Actions自体も「コード量を減らす」ことを目的としておりAPIルートや
fetch
の記述を省略できます。tRPCを併用すると、既存のtRPC風の記述でServer Actionを定義できるため学習コストが低く、APIルートレスで直感的なコーディングが可能です。例えば、ページルーター時代にtRPCを使っていた場合でもApp Router + Server Actions上で従来と同じ構文でロジックを記述し、裏側のネットワーク処理はNext.jsが担うので、移行がスムーズです。さらにAPIとUIコードのコロケーション(同一ファイル/近接した場所での管理)により、関連するフロントとバックのコードをまとめやすく、保守性が向上します。 -
柔軟なアーキテクチャと移行性: tRPC + Server Actions構成では、必要に応じて同じビジネスロジックをServer Action経由でも従来型のAPI経由でも公開できる柔軟性があります (Using Server Actions with tRPC | tRPC) たとえば、ある操作をNext.jsアプリ内部ではServer Actionとして呼び出しつつ、他のクライアント向けには従来のHTTP APIとして公開するといった選択も可能です。Server ActionsはあくまでNext.js内での仕組みですが、tRPCの抽象化に乗せておけば将来的にNext.js外(別サーバーやサーバーレス関数)に切り出すことも比較的容易です。既存プロジェクトでtRPCを使っている場合、一部のエンドポイントだけ徐々にServer Actionsに移行するといった段階的導入も簡単で、すべてを書き直す必要はありません (Using Server Actions with tRPC | tRPC)
-
パフォーマンスの利点: Server Actionは通常のAPIルートと異なり、Next.jsがビルド時にシリアライズされた形で関数呼び出しを繋いでくれるため、クライアントからサーバーへの呼び出しがフレームワーク内部で最適化されます。ネットワークレイヤを意識しなくて良い分、不要なHTTPオーバーヘッドが省かれ、低レイテンシーです (Using Server Actions with tRPC | tRPC) tRPCを組み合わせても、その呼び出しはServer Actionの仕組みに乗るためパフォーマンス上の大きなペナルティはありません。むしろ従来tRPC単体でReact Queryを介していた通信をServer Actionsに置き換えることで、不要なクライアント状態管理やシリアライズコストを削減できるケースもあります(※後述のNext Safe Actionと同様、純粋な関数呼び出しになるためです)。なお、tRPCの型推論が高度なためにTypeScriptサーバーが重くなるという指摘もありますが (tRPC vs Server Actions : r/nextjs) それは大規模プロジェクトの場合であり、適切にモジュール分割すれば運用可能です。
以上のように、Next.jsのServer Actionsという最新の仕組みにtRPCの成熟した型安全/API構築機能を加えることで、「シンプルさ」と「堅牢性」の両立が図れます。Next.js開発者は少ないコードでサーバーサイドロジックを実装しつつ、安全性やDXを損なわないメリットを享受できます。
Next.js Server Actions と tRPC の使用方法(実装例)
Next.js App Router環境下でServer ActionsとtRPCを組み合わせる手順を具体的に解説します。前提としてNext.js 13.4以降(App Router)と tRPC v11(β) が必要です (Using Server Actions with tRPC | tRPC) tRPC v11ではNext.jsのApp Router用にexperimental_nextAppDirCaller
というアダプタが提供されており、Server ActionをtRPCの手続きとして扱うことが可能になっています (Using Server Actions with tRPC | tRPC)
1. tRPCクライアントの初期化: まずtRPC
を初期化し、Server Actions用のプロシージャビルダーを作成します。従来はt.router()
等でエンドポイントを定義しましたが、Server Actionでは単一の関数として動作させるため、t.procedure.experimental_caller(...)
を利用します。このメソッドにNext.js用アダプタexperimental_nextAppDirCaller
を渡すことで、Server Action呼び出し時の特殊な振る舞い(例えばReactのuseActionState
フックを使った場合のシグネチャ変化 (Using Server Actions with tRPC | tRPC) にも対応できます。加えて、メタデータspan
を定義しておくと各アクションの識別(ログ出力やトレース用途)に便利です (Using Server Actions with tRPC | tRPC)
// server/trpc.ts
import { initTRPC, TRPCError } from '@trpc/server';
import { experimental_nextAppDirCaller } from '@trpc/server/adapters/next-app-dir';
interface Meta { span: string; } // 各アクション識別用メタデータ型
const t = initTRPC.meta<Meta>().create();
// Server Actions用のベースプロシージャを作成
export const serverActionProcedure = t.procedure.experimental_caller(
experimental_nextAppDirCaller({
pathExtractor: ({ meta }) => (meta as Meta).span, // spanメタデータで識別
})
);
上記により、serverActionProcedure
を基底としてtRPCの各種機能(入力スキーマやミドルウェア)を組み込んだ「Server Action関数」を定義していけるようになります。
2. コンテキストとミドルウェアの設定: 次に、認証情報など各アクションで共通して使いたい情報をコンテキストに注入します。Server ActionsではHTTPリクエストごとのコンテキスト(createContext
)がないため、ミドルウェアを利用してコンテキストを設定します (Using Server Actions with tRPC | tRPC) 例えば現在ログイン中のユーザ情報をセッションから取得し、t.procedure.use(...)
で全アクションのコンテキストにuser
として注入できます (Using Server Actions with tRPC | tRPC) さらに認可用に保護されたプロシージャを作りたい場合、認証チェックを行うミドルウェアを重ねます。以下はユーザが存在しなければエラーを投げるprotectedAction
の例です (Using Server Actions with tRPC | tRPC)
// server/trpc.ts (続き)
// ユーザ情報をコンテキストに載せるミドルウェア
export const serverActionProcedure = t.procedure.experimental_caller(...).use(async (opts) => {
const user = await getCurrentUser(); // セッションからユーザ取得(仮想関数)
return opts.next({ ctx: { user } });
});
// 未ログインの場合はUnauthorizedエラーを出す保護ミドルウェア
export const protectedAction = serverActionProcedure.use((opts) => {
if (!opts.ctx.user) {
throw new TRPCError({ code: 'UNAUTHORIZED' }); // 認証エラー
}
// ctx.userがnullでないことを保証して次へ
return opts.next({ ctx: { ...opts.ctx, user: opts.ctx.user } });
});
このようにtRPC
のミドルウェア機構を活用して、Server Actionの実行前後に共通処理を挟み込めます(認証・ログ・エラーハンドリング等)。next-safe-actionもバージョン7以降で同様のミドルウェアシステムを備えており、仕組みはtRPCに非常に近いものです (Middleware | next-safe-action)
3. アクション関数の定義: 準備ができたら、実際のサーバーアクション(ビジネスロジック)を定義します。Server Components配下の適当な場所(例: app/_actions.ts
)に以下のような関数を作成します:
// app/_actions.ts – サーバーアクション定義
'use server'; // Server Actionであることを示すディレクティブ
import { z } from 'zod';
import { protectedAction } from '../server/trpc'; // 上記で作成した保護付きプロシージャ
export const createPost = protectedAction
.input(z.object({ title: z.string() })) // 入力スキーマ定義(タイトルは文字列)
.mutation(async ({ ctx, input }) => { // ミューテーション(データ変更)処理
// ここでctx.user(認証ユーザ)を利用してDBに新規ポストを作成するなどの処理を行う
const { user } = ctx;
const { title } = input;
await db.post.create({ data: { title, authorId: user.id } });
});
上記のcreatePost
は、入力検証付きかつ認証済みユーザのみ実行可能なServer Actionです。.input()
により不正な入力はサーバー側で弾かれますし、.use()
で仕込んだ認証チェックにより未ログイン時は処理が実行されません。tRPC v11のexperimental_caller
を使っているため、.mutation()
で定義した関数そのものが直接呼び出し可能な関数としてエクスポートされます (Using Server Actions with tRPC | tRPC) すなわちcreatePost
の型は自動推論され、(input: { title: string }) => Promise という 「サーバー上で実行される関数」 になっています (Using Server Actions with tRPC | tRPC)
上記のように
tRPC
のビルダー構文でServer Actionを定義することで、わずかなコードで認証・バリデーション付きの安全なAPIが完成します (Using Server Actions with tRPC | tRPC)
4. クライアントからの呼び出し方法: 定義したServer Actionは、他のServer ActionやReactのクライアントコンポーネントから呼び出せます。例えば投稿作成フォームコンポーネントでの使用例を示します:
// app/post-form.tsx – クライアントコンポーネント
'use client';
import { createPost } from '../_actions'; // Server Actionをインポート
export function PostForm() {
return (
<form action={createPost} onSubmit={async (e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const title = formData.get('title') as string;
// JSロード後のリッチな挙動: 手動でServer Actionを呼び出し
await createPost({ title });
// 成功後のUI更新など
}}>
<input type="text" name="title" />
<button type="submit">投稿</button>
</form>
);
}
上記では、<form>
タグのaction
属性に直接createPost
関数を渡しています。こうするとノージャバスクリプトでもフォーム送信時にServer Actionが実行され、ページ遷移なしで結果処理できます(プログレッシブエンハンスメント) (Using Server Actions with tRPC | tRPC) 同時にonSubmit
ハンドラ内でもcreatePost
を呼んでおり、これはJSが有効な場合に実行されるパスです。e.preventDefault()
でブラウザ標準のフォーム送信を抑制し、フォームデータを取得してからawait createPost({ title })
と手動でServer Actionを呼び出しています (Using Server Actions with tRPC | tRPC) このようにフォームの宣言的な使用と、JavaScriptによるインタラクティブな使用の両方を両立できる点はServer Actionsの利点です。呼び出し側ではPromiseベースで結果を待つだけなので、完了後のUI更新(例えばモーダルを閉じる、トーストを表示する等)も自然な形で実装できます。
以上が基本的な使用方法です。追加でエラーハンドリングを行いたい場合、tRPCのTRPCError
を投げて状況に応じたメッセージを返す設計も可能です。Next.jsのガイドラインではServer Actionはエラーではなくエラーオブジェクトを返すことが推奨されていますが、tRPCでは将来的に型安全にエラーをハンドリングできる仕組みを整備中です (Using Server Actions with tRPC | tRPC)
tRPC Actions の特徴と Server Actions との関係性
前述のようにServer ActionsとtRPCはいずれもRPC的にフロントからバックエンド関数を呼び出す仕組みであり、「Server Actionsはバンドラー(ビルドツール)レベルで実現されたtRPC」と表現されるほどアプローチが似ています (Using Server Actions with tRPC | tRPC) 両者とも開発者に 「バックエンドの関数をフロントから直接呼べる」 体験を提供し、その際のネットワーク通信やシリアライズは隠蔽されます。この共通点のおかげで、tRPCを使ったServer Actions(tRPC Actionsと呼ぶことがあります)では自然な形で型安全な関数呼び出しが実現します。
しかし、Server Actions単体では不足しがちな機能(バリデーション、エラーハンドリング、認可など)を補完するのがtRPCの役割です (Using Server Actions with tRPC | tRPC) tRPC ActionsはtRPCのプロシージャビルダーとミドルウェアシステムを活用できるため、以下の特徴を持ちます:
-
入力・出力のスキーマ定義: Zodなどのスキーマライブラリで
.input()
や.output()
を指定することで、受け付けるデータ形式や返すデータ形式を明示できます。これにより、異常なデータが来た場合はサーバーで自動的に弾くため安全ですし、クライアント側でも型定義があるので誤った使い方ができません (Using Server Actions with tRPC | tRPC) (Using Server Actions with tRPC | tRPC) -
ミドルウェアによる共通処理: 認証チェックやロギング、コンテキストの付与などをミドルウェアチェーンとして挟めます。tRPCの
.use()
メソッドで処理を差し込む設計は非常に柔軟で、複数のミドルウェアを順序通りに実行したり、途中で処理を中断(例外送出)したりできます (Middleware | next-safe-action) (Middleware | next-safe-action) これにより認可が必要なアクションの保護(例:管理者ロールでなければエラーを返す等)や、リクエスト開始・終了時のログ記録などを横断的関心事として実装できます。 -
コンテキスト共有: tRPCでは
ctx
オブジェクトを通じてリクエスト単位のコンテキストデータ(ユーザ情報やDB接続等)を扱います。HTTPルータ経由ではcreateContext
で注入しますが、Server Actionでは前述のようにミドルウェア内でopts.next({ ctx })
とすることで同等のコンテキスト注入を行います (Using Server Actions with tRPC | tRPC) こうして各アクション内で共通のctx
経由ユーティリティが使えるようになります。 -
エラーハンドリングと型安全なエラー: tRPCは
TRPCError
によりエラーの種類を定義し、クライアント側でそれをハンドリングできます。Server Actionsとの組み合わせでも、例えば認可ミドルウェアでTRPCError('UNAUTHORIZED')
を投げれば、それをNext.jsがキャッチして適切なエラーとして扱います (Using Server Actions with tRPC | tRPC) 将来的にはNext.js推奨のエラーオブジェクト返却方式と組み合わせ、エラーも型で表現できるよう検討が進められています (Using Server Actions with tRPC | tRPC) -
柔軟な公開方法: tRPCで定義した手続きは、Server Actionとして使う以外にも、従来通りHTTP経由のAPIルータとして公開することも可能です。tRPC Actionsは 一種の「薄い皮」 のようなもので、内部ロジック自体はtRPCのプロシージャに書かれているため、それをtRPCルーターに組み込めばREST/GraphQLのようなエンドポイントにもできます。言い換えれば、tRPC ActionsはNext.js特有の呼び出し方をするtRPCエンドポイントであり、必要に応じて通常のAPIエンドポイントへ拡張/転用しやすいのが特徴です (Using Server Actions with tRPC | tRPC)
以上から、Server Actionsは仕組み、tRPCはツールキットと言えます。Server Actionsが提供する土台の上に、tRPC Actionsは様々な便利機能を載せている関係性です。どちらもTypeScriptで書かれ、エンドツーエンド型安全という思想を共有しているため両者の統合は自然であり、「Next.js公式のtRPC版」といった位置づけで捉えることもできます。
Next Safe Action と tRPC Actions の比較
Next.js界隈ではtRPC以外にもServer Actionsを強化するライブラリが登場しています。その代表が Next Safe Action(next-safe-action) です。Next Safe Actionは「型安全で検証可能なServer Actionsを簡単に定義する」ための軽量ライブラリで、エンドツーエンドの型安全性や各種バリデーション、ミドルウェア機能を提供しています (Using Server Actions with tRPC | tRPC) tRPC Actionsと目的は共通していますが、アプローチや細かなDXが異なります。以下の観点で両者を比較します。
-
セキュリティ(安全性): どちらも入力データの検証を重視しており、開発者にスキーマ定義を要求します。Next Safe ActionはZodをデフォルトに、Valibot/Yup/TypeBoxなど複数のバリデーションライブラリに対応しているのが特徴です (Getting started | next-safe-action) (Getting started | next-safe-action) 一方tRPCは主にZodを用いて入力チェックを行います。認証・認可に関して、Next Safe Actionでもミドルウェアによる認可制御が可能であり(例えば全アクションに対する共通ミドルウェアや、特定アクション実行前の認可チェックを容易に記述できます (Middleware | next-safe-action) (Middleware | next-safe-action) 、tRPCと同等のことが実現できます。したがって適切に実装すれば両者ともセキュアですが、Next Safe Actionは「安全に使うための作法」をパッケージ化しており、よりデフォルトで安全な設計(安全第一のプリセット)になっていると言えます。
-
型安全性: いずれもTypeScriptの型システムをフルに活用しており、サーバーで定義した型がそのままクライアントに伝播する点は共通です (Using Server Actions with tRPC | tRPC) tRPCは長年の実績があり複雑なネスト型やルーター構成でも型推論が効く点が強みです。Next Safe Actionも型安全な設計で、たとえば
createSafeActionClient()
で生成するクライアントには入力型・出力型が紐付いたメソッドが定義されます。違いを挙げるとすれば、Next Safe Actionは複数のバリデーションライブラリに対応するため型定義の融通が効く点です。Zod以外を使いたい場合、tRPCでは自前でパーサーを用意する必要がありますが、Next Safe Actionは公式にYup等のアダプタを用意しています (Getting started | next-safe-action) (Create the client | next-safe-action) また出力型の検証もNext Safe Actionはサポートしており (Type safe Server Actions in your Next.js project | next-safe-action) サーバーからのレスポンスを期待通りの型かチェックする仕組みもあります(tRPCでも.output()
指定で可能)。 -
DX(開発者体験)と習熟コスト: Next Safe Actionはシンプルさを重視しており、初期設定も
createSafeActionClient()
を呼ぶ程度で、あとはdefineAction
で関数を定義する流れです (Getting started | next-safe-action) (Create the client | next-safe-action) Next.js 14以降で動作し、React Hooks FormやTanStack Queryとの連携などモダンなユースケースを意識した設計になっています。特にフォームとの親和性は高く、<form action={...}>
を使った場合の取り扱いや、楽観的UI更新のためのuseOptimisticAction
フックなどDXを向上させる補助機能があります (Type safe Server Actions in your Next.js project | next-safe-action) 一方tRPC Actionsは、既存のtRPCユーザには馴染み深いものの、導入にはinitTRPCやプロシージャ構築といった下準備が必要でコード量もやや多めです。また現時点(2024年時点)ではServer Actions対応が実験段階(v11β)であり、安定版での使用にはもう少し時間が必要かもしれません (Trpc server actions - tRPC) (Trpc server actions - tRPC) React Queryに依存しない使い方が可能になった反面、サーバーサイドでのデータ取得は開発者が適宜実装する必要があります(Next Safe Actionも同様に、データ取得そのものはORMやクエリを自分で書くことになります)。総じて、「手軽にNext.jsのApp Routerで型安全なActionを使いたい」のであればNext Safe Actionのほうがセットアップが簡単であり、「既にtRPCのエコシステムに乗っている/高度なカスタマイズをしたい」場合にはtRPC Actionsが柔軟と言えるでしょう。 -
機能セット: 提供する機能面では重複が多いですが、注目すべき違いとしてNext Safe ActionはNext.js専用に特化しているため、フォームActionのステート管理やエラーのハンドリング方法などNext.jsのベストプラクティスに沿ったユーティリティが揃っています(例:
useActionState
との連携や、エラーをエラーオブジェクトとして返す仕組みなど)。一方tRPCはフレームワーク非依存の汎用RPCなので、Next.js外でも使える利点があります。その代わりNext.js特有の機能については自前でカバーする必要があり、例えばファイルアップロードや最適化されたリアクティブUI更新は独自に工夫する場面もあるでしょう。ただ、tRPCはコミュニティが非常に活発で情報も豊富なため、Next Safe Actionにない機能も中間ウェアやユーティリティを自作して補える余地があります。例えばOpenTelemetryを用いた分散トレースを入れたい場合、tRPCはプラグインが既に存在します (Using Server Actions with tRPC | tRPC) (Using Server Actions with tRPC | tRPC) -
性能とオーバーヘッド: 両者とも実行時にはNext.jsのServer Actions機構上で動くため、パフォーマンス上の差は限定的です。ネットワーク往復を最適化している点は共通で、処理系の差異(tRPCの方が多少ライブラリコードが多い程度)は通常のWebアプリでは体感できないレベルでしょう。むしろ、どちらを使うにせよビジネスロジックが整理されることで無駄な処理が減り、結果的に効率が上がることが期待できます。強いて言えば、tRPCは大量のエンドポイントを定義するとビルド時の型チェックコストが上がる懸念 (tRPC vs Server Actions : r/nextjs) ありますが、Next Safe Actionでも巨大なスキーマを扱えば同様の問題は起こり得ます。この点は設計とスケーリングの問題であり、ツール固有の性能問題ではありません。
まとめると、Next Safe Action はNext.jsアプリ内での手軽さ・DX向上にフォーカスしたソリューションで、tRPC ActionsはtRPC由来の包括的なタイプセーフ機能をNext.js上で活かすためのソリューションです。どちらもServer Actionsを強力に補完しますが、その思想と適用範囲に若干の違いがあります。
ユースケース別の選択: tRPC Actions vs Next Safe Action はどちらを選ぶべきか
どちらのアプローチも強力ですが、プロジェクトの状況や要求に応じて適切な選択をすることが重要です。以下にユースケース別の考察を示します。
-
既存のtRPCベースのプロジェクト: もし既にページルーター時代からtRPCを使用しており、Router/Procedureの定義が多数あるようなプロジェクトなら、tRPC Actionsを採用して移行コストを抑えるのが適しています。既存のビジネスロジックや型定義を再利用しつつ、必要なエンドポイントから順次Server Actionsに置き換えていけます (Using Server Actions with tRPC | tRPC) このように部分的にServer Actions化することで、新機能は効率良く実装しつつ、古いAPIも段階的にリファクタリングできます。tRPCのエコシステム(クライアントライブラリ、キャッシュ戦略、認証ミドルウェアなど)を引き続き活用できる点もメリットです。
-
複数クライアント(Web以外)から同一バックエンドにアクセスする必要がある場合: モバイルアプリや他のサービスからも利用されるAPIを構築する場合、tRPCを使用してHTTP経由のAPIエンドポイントを持つ設計が適しています。tRPC Actionsで書いた処理をそのままHTTPルータに組み込んだり、あるいはページルーターとの併用でtRPC HTTP APIを提供することもできます。Next Safe ActionはNext.js内部での呼び出しに特化しているため、他のクライアントへの公開には不向きです。将来Next.js以外の環境にバックエンドを分離する可能性があるなら、tRPCを使っておく方が移植性が高いでしょう。
-
新規のNext.js App Routerプロジェクトで、フロントエンド中心の開発: バックエンドを大規模に作り込む予定がなく、主にNext.js内で完結するWebアプリを作る場合はNext Safe Actionの方が手軽で実装しやすいでしょう。フォームのハンドリングやRouterとの親和性が高く、学習コストも低いです。「Next.js 14 + React 18.2」の環境を前提に最適化されており、最新のNext.js機能(
useOptimisticAction
やuseActionState
など)を活用した開発ができます。特にフロントエンド寄りの開発者やフルスタック初学者には、tRPCの抽象概念よりNext Safe ActionのシンプルなAPIの方が理解しやすいかもしれません。 -
リアルタイム機能や高度な状態管理が必要な場合: 例えばWebSocketを使ったリアルタイム通信や、クライアントサイドキャッシュを高度に最適化する必要がある場合、tRPC (+React Queryなど)の方が実績があります。tRPCは公式にWebSocketサポートやサブスクリプション機能も提供しており、これらを組み合わせてエンドツーエンドでリアルタイム機能を構築できます。Server Actionsは基本的にリクエスト・レスポンス型の処理なので、リアルタイム通信には直接対応していません。このような場合はServer Actionsに固執せず、tRPC経由の従来型APIやSocket通信を併用するのが現実的です。Next Safe Actionはリアルタイム通信機能を持たないため、必要なら別途実装が必要ですが、tRPCと共存させることも検討できます(同一アプリ内でServer ActionsとtRPC HTTP API/WSを併用すること自体は可能です。
-
とにかく最新のNext.js機能をフル活用したい場合: Next Safe Actionはコミュニティで注目度が高く、Theo氏(t3.gg)など有名開発者も評価しています (Type safe Server Actions in your Next.js project | next-safe-action) Next.jsのアップデートにも素早く追随しており、Next.js 15での
useStateAction
(Server Actionの状態管理フック)にも対応済みです (Getting started | next-safe-action) 一方tRPC v11は開発中とはいえ、tRPC自体のアップデートサイクルも活発です。最新のNext.jsの実験的機能を積極的に使いたい場合、Next Safe Actionはその名の通り安全にそれらを扱うラッパーを提供してくれる点で心強いでしょう。逆に、新機能の安定性よりも実績や信頼性を重視する現場では、tRPC(もしくは従来のREST/GraphQL)が選好されるかもしれません。 -
両者を組み合わせるケース: 理論上、同一プロジェクトでtRPC ActionsとNext Safe Actionを併用することもできます。しかしAPIの定義方法やミドルウェア体系が二重になるため、よほどの理由がない限りおすすめしません(ある開発者は「両方使うとシステムが統一されず複雑さが増す」と指摘しています (feat: Merging with the next-safe-action library · Issue #6241 · trpc/trpc · GitHub) 。どうしても一部機能だけ別ライブラリを使いたい場合を除き、基本的にはどちらか一方を選択してプロジェクト全体で統一した方がDX・保守性の面で有利です。先述の通り段階的移行で一時的に両方が共存することはあり得ますが、最終的な構成としてはシンプルにまとめる方が望ましいでしょう
総括すると、「Next.js App Router上での最適なDXとシンプルさ」を求める場合は Next Safe Action、
「他環境への展開も視野に入れた包括的な型安全RPC」を求める場合は tRPC Actions、
といった基準で選択するのが適切です。それぞれの強みを理解し、自分たちのユースケースに合ったツールを選びましょう。いずれにせよ、どちらのアプローチでもServer Actions自体の利点(コードコロケーション、ネットワーク処理の抽象化、型安全な関数呼び出し)は享受できますので、Next.js 13+ の開発では「APIルートをゴリゴリ書くより、Server Actions (+ 適切な型安全ライブラリ)」という流れが今後ますます主流になっていくと考えられます。
最後に、公式のtRPCブログでも触れられているように、Server Actionsは銀の弾丸ではなく用途を見極めて使うことが重要です (Using Server Actions with tRPC | tRPC) クライアント側状態が複雑な箇所ではあえてReact Queryや従来のmutate関数を使うほうが楽なこともあります。また、Next.jsを使わない環境では依然としてtRPCや他の通信手段が必要です。Server ActionsとtRPC/Next Safe Actionは手段であり目的ではないことを念頭に、適材適所で組み合わせていきましょう。今後それぞれのツールがアップデートされ、より安定したエコシステムが整っていくことに期待できます。
参考資料: 本稿の内容は公式ブログ (Using Server Actions with tRPC | tRPC) (Using Server Actions with tRPC | tRPC) コミュニティの知見 (tRPC vs Server Actions : r/nextjs) (Using Server Actions with tRPC | tRPC) もとにまとめています。詳細な実装例についてはtRPC公式の解説記事「Using Server Actions with tRPC」 (Using Server Actions with tRPC | tRPC) (Using Server Actions with tRPC | tRPC) Next Safe Actionのドキュメント (Type safe Server Actions in your Next.js project | next-safe-action) (Type safe Server Actions in your Next.js project | next-safe-action) 参照してください。それぞれの最新の仕様変更については、GitHubリポジトリやコミュニティからの情報を追うことをおすすめします。