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

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

React Server Components(RSC)は、サーバ側で実行され HTML として返ってくる新しい React コンポーネントの種類です。クライアント JS を出力せず DB や API を直接叩ける一方で、「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 Router。Vercel が AI 時代に存在感を増す流れと同じく、バンドル削減 + ストリーミング + サーバ集約 という方向に Web 全体が動いている、その代表格。

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

ざっくり言うと、Server Components は サーバで動かす React コンポーネント で、「これまでの React コンポーネント」 とは 動く場所と使える機能 が違います。 「サーバで動くから速い」 という単純な話ではなく、「 クライアントに 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 の新版ではない

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

なぜ RSC が必要になったか

「React と Next.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 は、「 この境界を意識すること」 が新しい必須スキル です。

「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」 して埋め込めますが、「 use client」 を書いたファイルとその先」 はバンドルに乗る、と理解するのがコツです。

境界の伝播

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

RSC を Client から呼ぶには

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

なるべく境界は下に

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

秘密情報の漏洩防止

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

次の図は、このあと出てくる App Router のコード例(「UserPage」 と 「LikeButton」)を、境界の位置で描いたものです。

UserPage(RSC) async で DB を読む h1 / p(RSC) 構造は RSC LikeButton 'use client' import 先も Client サーバで完結 JS を送らない バンドルに乗る範囲
境界は上から下に流れる。Client は葉先だけにする

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

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 と組み合わせる場合も、「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 にする回避策が必要。

境界をどこに引くかを意識する

「境界をどこに引くか」 を意識するだけで、ほとんどの問題は解決します。慣れるまではエラーが多めですが、慣れてくると 「 自然と 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 も送る」、RSC は 「クライアントに JS を送らない種類のコンポーネント」 です。並べて使うもので、「SSR + RSC」 が App Router の標準的な構成になっています。

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

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

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

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

A. localStorage はクライアント専用 なので RSC では触れません。Cookie はサーバで 「cookies()」 API を使えば読めます。これにより 「ログイン中ユーザーで分岐」 のような処理を 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 の中核機能としてすでに 「標準」 です。React 19 でリリースされ、Remix(React Router) / Waku など Next.js 以外のフレームワークでも採用が進んでいます。「一過性のトレンド」 ではなく 「React の進化方向そのもの」 と捉えるのが現実的です。

参考リンク

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

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