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

React Server Components(RSC)とは何か?仕組み・Client Components との違い・Next.js App Router での使い方

React Server Components(RSC)は、サーバ側で実行され HTML として返ってくる新しい React コンポーネントの種類です。クライアント JS を出力せず DBAPI を直接叩ける一方で、`useState』 等は使えません。Client Components との違い、`use client』 境界、Next.js App Router での使い方、データ取得・キャッシュの考え方を整理します。

先に要点

  • React Server Components(RSC) は、サーバで実行され、結果(HTML / シリアライズ済みツリー)だけがクライアントに届く 新種のコンポーネント。`使った分のクライアント JS が増えない』 が最大の価値。
  • サーバ専用なので、DB / 内部 API / ファイルシステム / 秘密情報を直接読める 一方、` useState』 `useEffect』 `onClick』 などの `状態とブラウザイベント』 系は使えない
  • インタラクション要素は ` Client Components』(`use client』 ディレクティブを書いたファイル) に切り出す。RSC は `データを取って木を組み立てる』、Client Components は `動かす』 という役割分担。
  • 事実上の本命採用先は Next.js App RouterVercel が AI 時代に存在感を増す流れと同じく、` バンドル削減 + ストリーミング + サーバ集約』 という方向に Web 全体が動いている、その代表格。

Next.js の App Router に切り替えたら use client』 って書かないとエラーが出るようになった』 RSC ってよく聞くけど Server Side Rendering とどう違うの? データ取得は useEffect + fetch』 でいいのか、それとも async コンポーネント』 で書くのか分からない』 ── React と Next.js が一気に進化したことで、書き方の前提』 が大きく変わったのが2024年以降の状況です。

ざっくり言うと、Server Components は サーバで動かす React コンポーネント』</strong> で、これまでの React コンポーネント』 とは 動く場所と使える機能 が違います。 サーバで動くから速い』 という単純な話ではなく、<strong> クライアントに JS を送らない』 という選択肢を React 自身に持たせた、というのが本質的な変化 です。

この記事では、2026年5月時点の React 19 / Next.js 15 系をベースに、RSC の仕組み・Client Components との境界・データ取得のコード・落とし穴・採用判断 を、`なんとなく書いていたが理屈が掴めていない』 レベルから一段上に行けるよう整理します。

まず2行で言うと

長文を読む前に、結論だけ先に固定しておきます。

RSC は `サーバで動く React コンポーネント』

サーバで JSX を実行 → 結果をクライアントに送る。クライアント側 JS バンドルには出ない。DB秘密情報を直接読める 代わりに、状態 / イベント / hooks は使えない

Client Components は `ブラウザで動く React コンポーネント』

`use client』 を書いたファイル。` useState』 `onClick』 `useEffect』 等の動的要素が使える。バンドルにも乗る。

RSC が Client を子として取り込める

RSC の中に Client Components を埋め込めるが、` Client Components の子は基本 Client 側』。境界が `ツリーの上から下』 に伝播する。

SSR とは別物

SSR は `クライアント JS を送りつつ、初回 HTML もサーバで作る』。RSC は `そもそもクライアント JS を送らない部分を作る』。並べて使える別レイヤー の話。

RSC = SSR の新版』 ではなく、SSR の世界に `クライアント JS を載せないコンポーネント』 という新しいピースを追加したもの』 と捉えるのが正確です。

なぜ RSC が必要になったか

`ReactNext.js は何が足りなくて RSC を導入したのか』 を見ると、設計意図が分かります。

①クライアント JS が肥大化する

SPA / SSR の標準では、`画面に必要なコンポーネントすべて』 がバンドルされる。`一度しか使わないテキスト UI』 にも JS のコストがかかる。

② データ取得の二段構え

` getServerSideProps』 → コンポーネントに props で渡す、という別レイヤーが必要だった。`コンポーネントから直接 DB を呼びたい』 が叶わなかった。

秘密情報がクライアントに漏れる事故

` API キーをクライアントに渡してしまう』 系の事故が、`境界が曖昧』 なせいで起きやすかった。`サーバでしか動かない部分』 を構造的に分離したい。

④ ストリーミングを活かしたい

サーバから `準備できた部分から順番に流す』 ことで体感速度を上げたい。RSC は ツリー単位でのストリーミング と相性が良い。

つまり ` クライアントに送らないでいい部分はサーバに留めたい』 という最適化を、コンポーネントモデルそのものに組み込んだ のが RSC です。

サーバとクライアント、それぞれで何ができて何ができないか

具体的な利用可否を表で押さえます。

機能 Server Components Client Components
JSX を書く
async / await を直接書く ○(`export default async function ...』) ×(基本)
DB クライアントを呼ぶ ○(Prisma / Drizzle / SQL 直接) ×
環境変数(秘密含む)を読む ○(サーバから) ×(`NEXT_PUBLIC_』 接頭辞のみ)
useState / useEffect / hooks ×
onClick / onChange など ×
Context を使う △(取得は不可、子として埋めるのは可)
クライアント JS への影響 なし(送らない) あり(バンドルに乗る)

どの機能はどっち側か』 を意識しないと、useState が使えない』 event handler は使えない』 系のエラーで詰まります。 RSC 時代の React は、<strong> この境界を意識すること』 が新しい必須スキル です。

`use client』 ディレクティブとは

Next.js / React は、ファイルの先頭に 'use client';』 と書くことで、このファイル(とその関数 / コンポーネント)はクライアント側』 と明示します。

'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

このファイルからエクスポートされるものは、それを使う側に Client 境界を引きます。 RSC からは普通に import』 して埋め込めますが、<strong> use client』 を書いたファイルとその先』 はバンドルに乗る、と理解するのがコツです。

境界の伝播

`use client』 を書いたファイルから `import』 した別ファイルは、自動的に Client 側として扱われる。`境界は上から下に流れる』 のが原則。

RSC を Client から呼ぶには

Client Components の 子として RSC を埋め込むには、`props.children』 として渡す形にする。`Client が直接 RSC を import』 はできない。

なるべく境界は下に

` 上のほうから use client』 にすると、丸ごとクライアントに送る羽目になる。`小さな葉の部分だけ Client』 が理想形。

秘密情報の漏洩防止

Client Components で `process.env.SECRET』 のような形で書くと、ビルド時に警告 / エラーになる。`サーバでしか読まない』 ことが構造的に守られる。

use client』 は <strong> ここから先はクライアントですよ』 の境界線 であって、`このファイルをクライアントに送る』 だけのスイッチではない、というのが正確な理解です。

Next.js App Router での書き方

実際の Next.js App Router で `データを取って表示する RSC』 はどう書くのか、コード例で確認します。

// app/users/[id]/page.tsx
import { db } from '@/lib/db';
import { LikeButton } from './LikeButton';

export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await db.user.findUnique({ where: { id: params.id } });

  if (!user) return <div>Not found</div>;

  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.bio}</p>
      <LikeButton userId={user.id} initialLikes={user.likes} />
    </div>
  );
}
// app/users/[id]/LikeButton.tsx
'use client';

import { useState } from 'react';

export function LikeButton({ userId, initialLikes }: { userId: string; initialLikes: number }) {
  const [likes, setLikes] = useState(initialLikes);
  return (
    <button onClick={() => setLikes(l => l + 1)}>♥ {likes}</button>
  );
}

注目点

`UserPage』 は `async』 で DB を直接読む。RSC 上で ` fetch / SQL / ORM 呼び出しが普通に書ける』 のが App Router の体験。

境界の引き方

`LikeButton』 だけ Client にして、それ以外の本体は RSC のまま。` バンドルされるのはボタンだけ』 という設計が自然に書ける。

セキュリティの安心感

` db.user.findUnique』 の呼び出しがクライアントに漏れる心配がない。`サーバの中だけで完結する』 と確信できる。

テストのしやすさ

RSC は基本 `関数として呼ぶ』 単位なので、`単体テストでは引数を渡して結果の JSX を検証』 という形でテストしやすい。

データ取得用のhooks がいらなくなった』 のが、App Router の体験を大きく変えた点です。 [tRPC](/articles/what-is-trpc-typesafe-api) と組み合わせる場合も、procedure をサーバコンポーネントから直接呼ぶ』 のような構成が普通に書けます。

データ取得とキャッシュ

App Router の RSC は、`fetch を直接書く』 だけで Next.js が裏でキャッシュを管理してくれます。

const res = await fetch('https://api.example.com/posts', {
  next: { revalidate: 60 }, // 60秒キャッシュ
});

デフォルト挙動

Next.js 15 系では、`fetch』 は `force-cache』 ではなく `no-store』 寄りがデフォルトに変更された。`常に最新を取る』 を基本にし、必要な場面で明示的にキャッシュする方針。

時間ベース無効化

`{ next: { revalidate: 60 } }』 のように指定すると、`60秒間はキャッシュを返す』 = ISR(Incremental Static Regeneration)的な動作になる。

タグベース無効化

`{ next: { tags: ['posts'] } }』 と書き、`revalidateTag('posts')』 でまとめて無効化。`投稿があったときだけキャッシュをクリアしたい』 ユースケースに合う。

不整合に注意

キャッシュ設定が散らばると `古い情報が表示される』 事故が起きやすい。`どのデータがどのキャッシュポリシーで動いているか』 を一覧化しておくのが運用上の安全策。

このキャッシュ設計と Vercel の請求が高くなる原因 は密接に関係します。 revalidate を小さくしすぎる』 と関数実行や帯域がそのまま課金に響くので、本当に短くする必要があるか』 を毎回考えるのが大事です。

RSC のよくある詰まりどころ

実際に開発していてよく出会う罠を整理しておきます。

①「useState を Server Components で使えない」エラー

そのファイルの先頭に `'use client';』 を書くか、`useState を使う部分だけ Client コンポーネントに切り出す』 のが正解。`コンポーネントごと Client』 にすると、無駄にバンドルが膨らむ。

② Client Component の子に async コンポーネントを書きたい

Client → Server の direct な import はできない。`props.children として上から渡す』 形に書き換える。`composition で境界を越える』 が React チームの推奨方針。

Context をどこに置くか

Context Provider は Client Component。RSC 内で `useContext』 はできない。`Provider を Client、子は RSC』 という配置が普通に書ける。

クライアント側でだけ動くライブラリ

` window』 を直接触るライブラリは、当然 Client Component でだけ動く。`use client』 を書いたファイルからのみ import するのが安全。

⑤ async コンポーネントのテストの書き方

RSC は `関数自身が Promise を返す』 ので、テストでは `await Component({...})』 のように呼んで結果の JSX を検証する。従来の `render()』 ベースのテストとは作法が違う。

⑥ 古いライブラリの互換性

`use client』 のないままサーバで実行できない依存(`window.matchMedia』 等を import 時に触る古い UI ライブラリ)はそのままだと動かない。`use client』 でラップするか、`next/dynamic』 で SSR off にする回避策が必要。

境界をどこに引くか』 を意識するだけで、ほとんどの問題は解決します。 慣れるまではエラーが多めですが、慣れてくると <strong> 自然と Client は葉先だけ』 という配置に向かう ようになります。

採用判断の軸

`RSC を採用すべきか』 の判断材料を整理しておきます。

向いている案件

① 中〜大規模 Next.js プロジェクト、② コンテンツ + 一部インタラクション、③ クライアント JS の重さがすでに問題、④ サーバとフロントTS で1人/小チームが書く構成。

急がなくていい案件

① まだ動いている Pages Router の小規模アプリ、② SSG が中心で十分早いブログ、③ RSC 非対応のライブラリに強く依存する案件。

フレームワークでの状況

Remix(現 React Router)、Waku、TanStack Start などでも RSC サポートが進行中。`Next.js 専用』 ではないことを覚えておくと、将来の選択肢が広がる。

学習時間の目安

すでに React に慣れている人なら、`境界の感覚』 を掴むのに 2 日〜1 週間程度。`use client』 を脳内で `読む』 練習を意識的にすると速い。

新規プロジェクトで Next.js なら、まず App Router + RSC で始めて、必要に応じて use client』 を貼る』 が、2026年現在の現実的な標準です。 v0 で UI を作る ような AI 連携の文脈でも、`生成された UI は Client、データ取得は Server』 という配置が自然に決まりやすくなります。

AI 時代の RSC

AI を組み込んだアプリで RSC が嬉しい場面はいくつかあります。

秘密情報の管理

OpenAI / Anthropic などの API キーは サーバでしか触れない ようにできる。`Client にキーが漏れる』 系の事故を構造的に防げる。

ストリーミング応答

AI の応答を サーバで受け取って、必要な単位でクライアントに送る。RSC + Server Actions + Suspense と組み合わせると、`AI が出してきたものを順次表示する UI』 が綺麗に書ける。

バンドルサイズの維持

AI 関連のライブラリは大きくなりがち。`サーバだけで使う AI ライブラリはバンドルに乗らない』 のが、ユーザー体感速度に効く。

構造化された UI 出力

AI が出した構造化データを Zod で検証 → RSC で JSX に組み立て → 必要な部分だけ Client、という流れは Zod と非常に相性が良い。

`AI が出力 → サーバが整形 → 必要な部分だけ Client で動かす』 という現代的な構造が、RSC によって自然に書けるようになったのが大きな変化です。

React Server Components に関するよくある質問

Q. RSC は SSR とどう違うのですか?

A. SSR初回 HTML をサーバで作る + クライアント側 JS も送る』、<strong>RSC</strong> は クライアントに JS を送らない種類のコンポーネント』 です。並べて使うもので、`SSR + RSC』 が App Router の標準的な構成になっています。

Q. すべてを RSC にすべきですか?

A. いいえ。動かす部分(ボタン、フォーム、ドラッグ操作など)』 はどうしても Client Components が必要です。<strong> 葉の部分だけ Client にして、構造は RSC』 という設計が一番素直に書けます。

Q. RSC からクライアントに `props』 で何でも渡せますか?

A. シリアライズ可能なものに限定されます。関数 / クラスインスタンス / DOM ノード / Promise(条件付き) は基本的には渡せません。`値や JSX』 は渡せます。

A. localStorage はクライアント専用 なので RSC では触れません。Cookie はサーバで cookies()』 API を使えば読めます</strong>。これにより ログイン中ユーザーで分岐』 のような処理を RSC で完結できます。

Q. RSC でエラーをハンドリングするには?

A. error.tsx』 を App Router のルートセグメントに置くと、その配下でエラーが起きたときに表示される Client Component が動きます。try / catch + JSX』 を直接書くことも可能です。

Q. RSC の本番運用は安全ですか?

A. 2024年〜2025年で大幅に成熟しました。Next.js を本番採用している企業の多くが App Router に移行済みで、本番運用上の問題は概ね小さい 状態です。とはいえ、`古いライブラリの非互換』 等は残るので、移行時には依存の点検が必要です。

Q. RSC は将来的に標準になりますか?

A. React の中核機能としてすでに 標準』</strong> です。React 19 でリリースされ、Remix(React Router) / Waku など Next.js 以外のフレームワークでも採用が進んでいます。一過性のトレンド』 ではなく `React の進化方向そのもの』 と捉えるのが現実的です。

参考リンク

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

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