nextjs-app-router-guide
Next.js App RouterでのServer Components / Server Actions / Route Handlers等の使い分けガイド。「Server ComponentとClient Componentの違い」「Server Actionsの使い方」「revalidatePath/revalidateTagの違い」などの質問に回答する際に参照する。
When & Why to Use This Skill
This Claude skill serves as a comprehensive technical guide for the Next.js App Router architecture. It provides developers with a clear decision-making framework for choosing between Server and Client Components, implementing Server Actions, and managing complex data mutation flows. By offering detailed comparisons and best practices for hooks and caching, it helps optimize web application performance and maintainability.
Use Cases
- Architectural Decision Making: Determining whether to use Server Components or Client Components based on interactivity, state management, and browser API requirements.
- Data Mutation Strategy: Choosing the correct implementation path between Server Actions for UI-driven updates and Route Handlers for public-facing HTTP APIs.
- UX Optimization: Implementing advanced React hooks such as useOptimistic for instant feedback, useFormStatus for pending states, and useActionState for handling validation errors.
- Cache Management: Selecting the appropriate revalidation strategy using revalidatePath, revalidateTag, or updateTag to ensure data consistency and high performance.
| name | nextjs-app-router-guide |
|---|---|
| description | Next.js App RouterでのServer Components / Server Actions / Route Handlers等の使い分けガイド。「Server ComponentとClient Componentの違い」「Server Actionsの使い方」「revalidatePath/revalidateTagの違い」などの質問に回答する際に参照する。 |
Next.js App Router 使い分けガイド
最小の判断フロー
何を実現したい?
├─ UIコンポーネント?
│ ├─ Yes → interactivity必要?(state/handlers/browser API)
│ │ ├─ Yes → Client Component
│ │ └─ No → Server Component
│ └─ No(関数/ロジック) → クライアントから呼ぶ?
│ ├─ No → server-only関数(import 'server-only')
│ └─ Yes → HTTP API公開?
│ ├─ Yes → Route Handler
│ └─ No → Server Function('use server')
│ └─ mutation文脈?(form action等)
│ └─ Yes → Server Action
Server Action選択後のキャッシュ更新:
- stale許容 →
revalidateTag(profile="max"でstale-while-revalidate) - 即時反映必須 →
updateTag - パス指定 →
revalidatePath
関連Hooksの使い分け
| Hook | 用途 | 典型例 |
|---|---|---|
useTransition |
UIをブロックせず低優先度更新 | 保存中も入力可能にしたい |
useFormStatus |
フォーム送信のpending状態取得 | 二重送信防止、スピナー表示 |
useActionState |
action結果に基づくstate管理 | バリデーションエラー表示 |
useOptimistic |
楽観的UI更新 | いいねボタンの即時反映 |
Q1. Server ComponentsとClient Componentsの違いは?
環境(server / browser)ごとの「できること」で分ける。
| 用途 | 選択 |
|---|---|
state / event handlers / useEffect / browser API |
Client Component |
| DB/API近接でのデータ取得、秘密情報利用、JS削減、ストリーミング | Server Component |
App Routerではlayouts/pagesはデフォルトでServer Component。Client Componentが必要な場合のみファイル先頭に'use client'を付ける。
Q2. Server FunctionsとServer Actionsの違いは?
「クライアントからネットワーク経由で呼べるか」で分ける。
Server Function('use server')
サーバーで動く非同期関数で、クライアントからネットワークリクエスト経由で呼べるためasyncである必要がある。use serverをファイル先頭に置けば、そのファイルの全exportがserver側になる。
Server Action(= mutation文脈)
「action / mutation文脈」ではServer FunctionsはServer Actionsとも呼ばれる。<form action={...}>や<button formAction={...}>に渡すと自動的にその扱いになり、Next.jsのキャッシュ機構と統合され、更新後UIと新データを1回のサーバー往復で返せる。
普通のserver-only関数
クライアントから呼ぶ必要がないユーティリティは「普通のserver-only関数」で十分。import 'server-only'でマークすると、Client Componentがimportした場合にビルドエラーにできる。
Q3. Server Actionsはどこに置く?
「どこから呼ぶか」で制約が変わる。
- Server Component内でインライン定義:関数先頭に
'use server'を置く - 別ファイルで定義:ファイル先頭に
'use server'を置く
Client Componentsは「モジュール先頭の"use server"」で定義されたactionしかimportできない。つまりClient Componentから使いたい場合は、専用ファイルを作る必要がある。
// actions.ts
'use server'
export async function createPost(formData: FormData) {
// Server Actionの実装
}
Q4. Route HandlersとServer Actionsの使い分けは?
「HTTP APIとしての入出力が必要か」で分ける。
| ユースケース | 選択 |
|---|---|
ブラウザから直接fetch('/api/...')したい |
Route Handler |
| Webhookを受けたい | Route Handler |
| 外部クライアントに公開したい | Route Handler |
| フォーム送信・ボタン操作などUIからの更新 | Server Action |
Route Handlersはapp/**/route.tsに配置し、Web標準のRequest/Response APIを使う。Server Actionsは裏側でPOSTを使い、Next.jsのキャッシュ/UI更新と統合される。
Q5. useTransitionはいつ使う?
「UIをブロックせずに低優先度の更新を裏で進めたい」とき。
useTransitionは「UIをブロックせずにstateを更新する」ためのReact Hookで、isPendingとstartTransitionを返す。
const [isPending, startTransition] = useTransition()
function handleSave() {
startTransition(async () => {
await saveData() // この間もUIは操作可能
})
}
Server Actionsは慣習的にstartTransitionと一緒に使われ、<form action>経由ならそれが自然に成立する。
Q6. useFormStatusはいつ使う?
「フォーム送信のpending状態」をUIに反映したいとき。
useFormStatusは直近のform submissionのステータス情報を返すHook。
function SubmitButton() {
const { pending } = useFormStatus()
return <button disabled={pending}>送信</button>
}
注意:pendingを正しく取るには<form>の中でレンダリングされるコンポーネント内で使う必要がある。
Q7. useActionState / useOptimistic はいつ使う?
useActionState
「form actionが呼ばれたときに更新されるstate」を作りたいとき。
const [state, formAction, isPending] = useActionState(
async (prevState, formData) => {
const result = await submitForm(formData)
return result // これが次のstateになる
},
initialState
)
return <form action={formAction}>...</form>
バリデーションエラーの表示や、サーバーからの応答に基づくUI更新に便利。
useOptimistic
「非同期アクション実行中だけ楽観的に違うstateを見せたい」とき。
const [optimisticLikes, addOptimisticLike] = useOptimistic(
likes,
(state, newLike) => [...state, newLike]
)
async function handleLike() {
addOptimisticLike({ id: 'temp', pending: true }) // 即座にUI反映
await likePost() // サーバー処理完了後、実際の値に置き換わる
}
「いいね」ボタンなど、即座にフィードバックを見せたいUIに有効。
Q8. revalidatePath()はいつ使う?
「特定パスのキャッシュをオンデマンドで無効化したい」とき。
revalidatePathは特定pathのcached dataをオンデマンドでinvalidateできる。Server FunctionsとRoute Handlersで呼べるが、Client Componentsでは呼べない。
挙動の違いに注意:
- Server Functionで呼ぶ:影響パスを見ているときUIが即時更新されうる。「訪問済みページが次回ナビゲーションでrefreshされる」挙動は一時的
- Route Handlerで呼ぶ:次にそのpathが訪問されたときにrevalidateされる
動的セグメントのパターン指定:
revalidatePath('/posts/[id]', 'page')
Q9. revalidateTagとupdateTagの違いは?
「キャッシュをタグでまとめて制御」し、読み取り一貫性の要件で使い分ける。
| 関数 | 特徴 | ユースケース |
|---|---|---|
revalidateTag |
profile="max"指定でstale-while-revalidate(裏でfreshを取る間staleを返す) |
更新が多少遅れてもよいコンテンツ |
updateTag |
staleを返さずfreshを待つ | read-your-own-writes(更新直後に必ず最新を見せたい) |
updateTagはServer Actions内でのみ使える。
tag系APIが効くためには、読み取り側でタグ付けが必要:
fetch(... { next: { tags: [...] }})use cache+cacheTag(...)
Q10. serverActions設定はいつ使う?
「CSRF対策(プロキシ経由)」や「送信ボディが大きい」とき。
// next.config.js
module.exports = {
experimental: {
serverActions: {
allowedOrigins: ['my-proxy.com'], // CSRF対策
bodySizeLimit: '2mb', // デフォルト1MB
},
},
}
セキュリティの仕組み(Origin/Hostチェック)
Next.jsのServer ActionsはOriginヘッダとHostを比較し、一致しない場合はActionを拒否する。裏側ではPOSTのみがactionsをinvokeできる。
Q11. 「action / mutation文脈」って結局なに?
「読み取り(read)ではなく、書き込み(mutation)を起こす操作」の文脈。
- Server Function:サーバーで動く非同期関数の総称
- Server Action:その中でも「mutationを起こす文脈」で使われるもの
<form action=...>や<button formAction=...>で自然に発火し、キャッシュ/UI更新と統合される。
Q12. Cache Components / use cache はいつ使う?
「コンポーネントや関数をキャッシュ可能としてマークしたい」とき(Next.js 16+のopt-in機能)。
// ファイル全体をキャッシュ可能に
'use cache'
export async function getCachedData() {
// この関数の結果がキャッシュされる
}
Cache ComponentsはNext configでcacheComponentsフラグを有効化して使うopt-in機能。
Server Actionsの制約
- mutation向け:データ取得(fetch用途)には推奨されない
- 直列実行:クライアントは「1つずつ順番にdispatchしてawait」するため並列フェッチには向かない
- シリアライズ制約:引数・戻り値はシリアライズ可能である必要がある
並列でデータを取りたい場合:
- Server Componentsでのデータフェッチ
- 1つのServer Function内で
Promise.all
まとめ
- デフォルトはServer Component、state/handlers/browser APIが必要なときだけClient Component
- UIからの更新はServer Action、HTTP API公開はRoute Handler
- Server Actionsはmutation向け、並列データ取得にはServer Componentsを使う
- キャッシュ制御は
revalidatePath/revalidateTag、即時反映(read-your-own-writes)ならupdateTag - server-onlyにしたいモジュールは
import 'server-only'で漏洩防止 - フォームUIには
useFormStatus/useActionState/useOptimisticを活用