本文へ移動
verified onnext@16.3.3react@19
最終検証日 2026-08-27
Next.js道場

Server Function の渡し方

関数は Client Component に渡せませんが、use server を書いた Server Function だけは渡せます。

#例外はひとつだけ

Server Component から Client Component へ関数は渡せません。渡すとビルドが落ちます。

// ❌ Event handlers cannot be passed to Client Component props.
<Button onClick={() => save()} />

例外は 'use server' を書いた関数、Server Function だけです。

// ✅ 渡せる
<Button onSave={save} />

#書き方は2通り

ファイルの先頭に書く。 そのファイルが export する関数すべてが対象になります。Client Component から import できるのはこの形だけです。

// app/actions.ts
'use server'

export async function submit(value: string) {
  // サーバーで実行される
}

関数の先頭に書く。 その関数だけが対象になります。Server Component の中で、その場で定義するときに使います。

export default function Page() {
  async function save(name: string) {
    'use server'
    await db.user.update({ name })
  }

  return <EditPost onSave={save} />
}

その場でしか使わない小さな更新なら後者が読みやすく、複数の画面から呼ぶものや、テストを書きたいものは前者に切り出します。

#「サーバーで動かす」という意味ではない

'use server' を「この処理をサーバーで動かす指示」だと読むと、置き場所を間違えます。

Server Component はもともとサーバーで動いています。書く必要はありません。

'use server' の意味は、サーバーにある関数を、クライアントから呼べるようにすることです。境界に穴を1つ開ける操作だと考えてください。

'use client' と対になっているように見えますが、役割は対称ではありません。

指示意味
'use client'ここから先はブラウザにも送る
'use server'ここをクライアントから呼べる入口にする

#中身は届かない。呼び出しは届く

Server Function を props で渡したとき、ブラウザに届くのはどこを呼べばよいかという参照だけです。関数の中のコードは届きません。

実際に、中に特徴的な文字列を入れた Server Function を Client Component へ渡してビルドし、成果物を検査しました。HTML にも RSC ペイロードにも、配信される JavaScript にも、その文字列は含まれていませんでした。

ただし、見えないのはコードであって、通信ではありません。

開発者ツールのネットワークタブを開けば、呼び出しの引数と戻り値はそのまま観察できます。参照が分かれば、画面を経由せずに呼ぶこともできます。

だから、次の3つは関数の中で必ず行います。

  1. 認証と権限の確認。 公式ドキュメントも、トークンを引数で受け取らず Cookie やヘッダーから読むよう案内しています
  2. 引数の検証。 クライアントから来た値は、形も範囲も信用しない
  3. 戻り値を絞る。 データベースの行をそのまま返さない
'use server'

export async function createUser(data: { name: string }) {
  const session = await auth()
  if (!session?.user) throw new Error('Unauthorized')

  const user = await db.user.create({ data })
  return { id: user.id, name: user.name }   // 行をそのまま返さない
}

戻り値はシリアライズされてクライアントへ送られます。渡せる値の制限はServer から Client へ渡せる値と同じです。

#定数を同じファイルに置かない

'use server' を書いたファイルから export できるのは非同期関数だけです。

'use server'

export const CATEGORIES = ['bug', 'question']   // ❌
A "use server" file can only export async functions, found object.

これは export したものがすべて「クライアントから呼べる入口」として登録されるためで、呼べないものを置くことはできません。

定数は別のファイルに移します。このサイトを作っているときも同じ失敗をして、問い合わせ画面のビルドが落ちました。型だけの export は消えるので、typeinterface は同じファイルに残して構いません。

#まとめ

  • 関数は渡せない。Server Function だけが例外
  • 'use server' は「サーバーで動かす」ではなく「クライアントから呼べるようにする」
  • 中身は届かないが、呼び出しは誰でもできる。認証・検証・戻り値の制限は関数の中で
  • 定数は別ファイルへ

境界を越えられない関数の話はEvent handlers cannot be passedに、関数を渡さずに済ませる形はClient Component の中に Server Component を置くにあります。

理解できたか試す

では、このコードはどうなりますか。

このファイルを別のコンポーネントから import してビルドすると、どうなりますか。

この問題を解くこのテーマの問題 3