RSC Payload とは。ブラウザに何が届くのか
Server Component のコードはブラウザに届きませんが、Client Component へ渡した props は表示していなくても全部届きます。
送られるのは「結果」であって「コード」ではない
Server Component を書いても、そのコードはブラウザに届きません。届くのは、サーバーで描画した結果です。
具体的には2つ送られます。
| 届くもの | 何のためか |
|---|---|
| HTML | 最初の表示に使う。JavaScript が来る前から読める |
| RSC ペイロード | React が画面を組み立て直すための木構造のデータ |
RSC ペイロードには、コンポーネントの構造と、境界を越えた props の値が入っています。開発者ツールのネットワークタブや、ページのソースから読めます。
境界を越えた props は、表示していなくても届く
ここが実務でいちばん重要です。
// app/admin/page.tsx(Server Component)
export default function Page() {
const key = process.env.ADMIN_KEY // NEXT_PUBLIC_ は付いていない
return <Table apiKey={key} /> // ← 越えた
}
このコードをビルドすると、成果物の中に ADMIN_KEY の値がそのまま入ります。画面に表示していなくても入ります。
このサイトでは、これを説明で済ませていません。この問題は、実際に Next.js 16.3.5 でビルドして、成果物に値が含まれることを毎回確かめています。
NEXT_PUBLIC_ が守るもの、守らないもの
| 書き方 | JS バンドル | プリレンダーされた HTML |
|---|---|---|
| NEXT_PUBLIC_X を Client で読む | 出る | 出る |
| X(接頭辞なし)を Server で読むだけ | 出ない | 出ない |
| X を Server で読んで props に入れる | 出ない | 出る |
よくある誤解が「NEXT_PUBLIC_ を付けていないから安全」です。
| 何が起きるか | |
|---|---|
NEXT_PUBLIC_ を付ける | その環境変数がクライアント側のバンドルに埋め込まれる |
| 付けない | 埋め込まれない |
| 自分で props として渡す | 付けていなくても届く |
NEXT_PUBLIC_ が制御しているのは「変数の埋め込み」だけです。自分の手で境界を越えさせた値は、その対象外です。仕組みが守ってくれるのはここまでで、あとは書いた人の責任になります。
使っていないプロパティも届く
受け取る側が読まなくても、渡したオブジェクトの中身は全部運ばれます。
const user = await getUser() // { id, name, passwordHash, ... }
return <Profile user={user} /> // Profile は name しか使わない
これでも passwordHash は届きます。型で { name: string } と宣言しても関係ありません。型は実行時には消えているので、何も削りません。
ORM が返した行をそのまま渡すのが危ない、というのはこの意味です。
越えなければ残らない
逆に、境界を越えなければ値は残りません。
export default async function Page() {
const key = process.env.ADMIN_KEY
const rows = await load(key) // サーバーの中で使い切る
return <div>{rows.length}</div> // 渡すのは件数だけ
}
これは実際に確かめて、成果物に値が含まれないことを確認しています。
安全なのは「使ったこと」ではなく「渡さなかったこと」です。
実務での書き方
1. 秘密はサーバーの中で使い切る
API キーが要るなら、その呼び出しごとサーバー側に置き、外へ出すのは結果だけにします。
2. 渡す形を明示的に組み立てる
const row = await db.user.findFirst()
const user = {
id: row.id,
name: row.name,
}
return <Profile user={user} />
面倒に見えますが、これ1つでシリアライズのエラーと情報漏れの両方が防げます。
3. レビューで見る場所を1つに絞る
「Client Component に渡している props に、見せてはいけないものが無いか」だけを見ればよくなります。境界がはっきりしているほど、確認は速く終わります。
確認のしかた
自分のページで確かめたいときは、ビルドした成果物を検索するのが確実です。
next build
grep -r "確かめたい文字列" .next/server/app
ブラウザで確かめるなら、ページのソースを表示して同じ文字列を探します。開発者ツールを開かない利用者には見えませんが、見ようと思えば誰でも見られるという前提で設計してください。
出典
- nextjs.org/docs/app/getting-started/server-and-client-components
- nextjs.org/docs/app/guides/environment-variables
このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。