nextjs について
nextjsは、Next.js App Routerの本番向けガイドを提供するスキルで、Next.js 16の変更点と移行時の課題を中心に扱います。App Routerアプリを開発・更新する開発者向けに、例、テンプレート、トラブルシューティング情報をまとめています。
主な機能
- 01Next.js 16の破壊的変更の解説
- 02Next.js 15からの移行ガイド
- 03Cache ComponentsとキャッシュAPIの解説
- 04ルートハンドラーとproxy変更の説明
- 05テンプレートとエラー解決策の提供
- 06セキュリティ情報とバージョン要件の整理
活用シーン
- 01App RouterプロジェクトのNext.js 16への移行
- 02非同期ルートAPIに合わせたコード更新
- 03キャッシュとパラレルルートの設定
- 04記載されたNext.jsエラーのトラブルシューティング
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill nextjsインストール後、Claude Code で/nextjsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.md.claude-plugin/plugin.jsoncommands/init.mdreferences/next-16-migration-guide.mdtop-errors.mdrules/nextjs.mdscripts/check-versions.shtemplates/app-router-async-params.tsxcache-component-use-cache.tsxpackage.jsonparallel-routes-with-default.tsxproxy-migration.tsroute-handler-api.tsserver-actions-form.tsx詳細
Next.js App Router - 本番環境向けのパターン
Version: Next.js 16.1.1 React Version: 19.2.3 Node.js: 20.9+ Last Verified: 2026-01-09
目次
- このスキルを使用する場合
- このスキルを使用しない場合
- セキュリティに関する注意喚起(2025年12月)
- Next.js 16.1 の更新
- Next.js 16 の破壊的変更
- Cache Components とキャッシュ API
- Route Handlers(Next.js 16 の更新)
- Proxy と Middleware の比較
- Parallel Routes - default.js が必須
- React 19.2 の機能
- Turbopack(Next.js 16 で安定版)
- よくあるエラーと解決策
- テンプレートとリソース
このスキルを使用する場合
重点:Next.js 16 の破壊的変更と知識の不足部分(2024年12月以降)。
以下が必要な場合は、このスキルを使用してください。
- Next.js 16 の破壊的変更(非同期の params、proxy.ts、parallel routes の default.js、削除された機能)
"use cache"ディレクティブを使った Cache Components(Next.js 16 の新機能)- 新しいキャッシュ API:
revalidateTag()、updateTag()、refresh()(Next.js 16 で更新) - Next.js 15 から 16 への移行(破壊的変更によるエラーを回避)
- 非同期のルートパラメーター(
params、searchParams、cookies()、headers()が非同期に変更) - default.js を使った Parallel Routes(Next.js 16 では必須)
- React 19.2 の機能(View Transitions、
useEffectEvent()、React Compiler) - Turbopack(Next.js 16 で安定版となり、デフォルトに設定)
- 画像のデフォルト設定の変更(Next.js 16 での TTL、サイズ、品質)
- エラーの防止(解決策付きで文書化された Next.js 16 のエラー 25 件)
このスキルを使用しない場合
以下の場合は、このスキルを使用しないでください。
- Cloudflare Workers へのデプロイ → 代わりに
cloudflare-nextjsスキルを使用 - Pages Router のパターン → このスキルの対象は App Router のみです(Pages Router はレガシーです)
- 認証ライブラリ →
clerk-auth、better-auth、またはその他の認証に特化したスキルを使用 - データベース統合 →
cloudflare-d1、drizzle-orm-d1、またはデータベースに特化したスキルを使用 - UI コンポーネントライブラリ → Tailwind と shadcn/ui には
tailwind-v4-shadcnスキルを使用 - 状態管理 →
zustand-state-management、tanstack-queryスキルを使用 - フォームライブラリ →
react-hook-form-zodスキルを使用 - Vercel 固有の機能 → Vercel プラットフォームのドキュメントを参照
- Next.js Enterprise の機能(ISR、DPR)→ Next.js Enterprise のドキュメントを参照
- デプロイ構成 → プラットフォームに特化したデプロイスキルを使用
他のスキルとの関係:
- cloudflare-nextjs:Next.js を Cloudflare Workers にデプロイする場合(Cloudflare にデプロイする場合は両方のスキルを併用)
- tailwind-v4-shadcn:Tailwind v4 と shadcn/ui のセットアップ用(このスキルと組み合わせて使用可能)
- clerk-auth:Next.js での Clerk 認証用(このスキルと組み合わせて使用可能)
- better-auth:Better Auth の統合用(このスキルと組み合わせて使用可能)
セキュリティに関する注意喚起(2025年12月)
重大:2025年12月、React Server Components を使用する Next.js に影響する、3 件のセキュリティ脆弱性が公表されました。
| CVE | 深刻度 | 影響を受けるバージョン | 説明 |
|---|---|---|---|
| CVE-2025-66478 | 重大(10.0) | 15.x、16.x | Server Component での任意コード実行 |
| CVE-2025-55184 | 高 | 13.x-16.x | 不正なリクエストによるサービス拒否 |
| CVE-2025-55183 | 中 | 13.x-16.x | エラーレスポンスでのソースコード漏えい |
要対応:直ちに Next.js 16.1.1 以降にアップグレードしてください。
npm update next
# Verify: npm list next should show 16.1.1+
参考資料:
Next.js 16.1 の更新(2025 年 12 月)
16.1 の新機能:
- Turbopack ファイルシステムキャッシュ(安定版):開発環境でデフォルトで有効になりました
- Next.js バンドルアナライザー:バンドル分析のための新しい実験的機能
- デバッグの改善:
next dev --inspectのサポートが強化されました - セキュリティ修正:CVE-2025-66478、CVE-2025-55184、CVE-2025-55183 に対応しました
Next.js 16 の破壊的変更
重要:Next.js 16 では、複数の破壊的変更が導入されています。Next.js 15 以前から移行する場合は、このセクションをよくお読みください。
1. 非同期ルートパラメーター(破壊的変更)
破壊的変更:params、searchParams、cookies()、headers()、draftMode() が非同期になり、await が必須になりました。
変更前(Next.js 15):
// ❌ This no longer works in Next.js 16
export default function Page({ params, searchParams }: {
params: { slug: string }
searchParams: { query: string }
}) {
const slug = params.slug // ❌ Error: params is a Promise
const query = searchParams.query // ❌ Error: searchParams is a Promise
return <div>{slug}</div>
}
変更後(Next.js 16):
// ✅ Correct: await params and searchParams
export default async function Page({ params, searchParams }: {
params: Promise<{ slug: string }>
searchParams: Promise<{ query: string }>
}) {
const { slug } = await params // ✅ Await the promise
const { query } = await searchParams // ✅ Await the promise
return <div>{slug}</div>
}
対象:
- ページ、レイアウト、ルートハンドラーの
params - ページの
searchParams next/headersのcookies()next/headersのheaders()next/headersのdraftMode()
移行:
// ❌ Before
import { cookies, headers } from 'next/headers'
export function MyComponent() {
const cookieStore = cookies() // ❌ Sync access
const headersList = headers() // ❌ Sync access
}
// ✅ After
import { cookies, headers } from 'next/headers'
export async function MyComponent() {
const cookieStore = await cookies() // ✅ Async access
const headersList = await headers() // ✅ Async access
}
Codemod:npx @next/codemod@canary upgrade latest を実行すると、自動的に移行できます。
Codemod の制限事項(コミュニティからの情報): 公式 Codemod は非同期 API の移行の約 80%に対応しますが、次のような例外には対応できません。
- カスタムフック内でアクセスされる非同期 API
paramsにアクセスする条件付きロジック- 外部パッケージからインポートされたコンポーネント
- 複数の非同期呼び出しを含む複雑なサーバーアクション
Codemod の実行後、自動修正できなかった箇所を示す @next-codemod-error コメントを検索してください。
クライアントコンポーネントの手動移行:
// For client components, use React.use() to unwrap promises
'use client';
import { use } from 'react';
export default function ClientComponent({
params
}: {
params: Promise<{ id: string }>
}) {
const { id } = use(params); // Unwrap Promise in client
return <div>{id}</div>;
}
テンプレートを参照:templates/app-router-async-params.tsx
2. Middleware から Proxy への移行(破壊的変更)
破壊的変更:Next.js 16 では middleware.ts は非推奨です。代わりに proxy.ts を使用してください。
変更の理由:proxy.ts は Node.js ランタイム(Edge ランタイムではありません)で実行されるため、ネットワーク境界が明確になります。これにより、エッジミドルウェアとサーバーサイドプロキシの違いがより明確になります。
移行手順:
- ファイル名を変更:
middleware.ts→proxy.ts - 関数名を変更:
middleware→proxy - 設定を更新:
matcher→config.matcher(構文は同じです)
変更前(Next.js 15):
// middleware.ts ❌ Deprecated in Next.js 16
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('x-custom-header', 'value')
return response
}
export const config = {
matcher: '/api/:path*',
}
変更後(Next.js 16):
// proxy.ts ✅ New in Next.js 16
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('x-custom-header', 'value')
return response
}
export const config = {
matcher: '/api/:path*',
}
注:Next.js 16 でも middleware.ts は引き続き動作しますが、非推奨です。今後も互換性を保つため、proxy.ts に移行してください。
テンプレートを参照:templates/proxy-migration.ts
リファレンスを参照:references/proxy-vs-middleware.md
3. Parallel Routes で default.js が必須に(破壊的変更)
破壊的変更:Parallel Routes では明示的な default.js ファイルが必須になりました。ファイルがない場合、ソフトナビゲーション時にルートでエラーが発生します。
構成:
app/
├── @auth/
│ ├── login/
│ │ └── page.tsx
│ └── default.tsx ← REQUIRED in Next.js 16
├── @dashboard/
│ ├── overview/
│ │ └── page.tsx
│ └── default.tsx ← REQUIRED in Next.js 16
└── layout.tsx
レイアウト:
// app/layout.tsx
export default function Layout({
children,
auth,
dashboard,
}: {
children: React.ReactNode
auth: React.ReactNode
dashboard: React.ReactNode
}) {
return (
<html>
<body>
{auth}
{dashboard}
{children}
</body>
</html>
)
}
デフォルトのフォールバック(必須):
// app/@auth/default.tsx
export default function AuthDefault() {
return null // or <Skeleton /> or redirect
}
// app/@dashboard/default.tsx
export default function DashboardDefault() {
return null
}
必須となった理由:Next.js 16 では、Parallel Routes がソフトナビゲーションを処理する方法が変更されました。default.js がない場合、クライアントサイドのナビゲーション時に一致しないスロットでエラーが発生します。
テンプレートを参照:templates/parallel-routes-with-default.tsx
4. 削除された機能(破壊的変更)
次の機能は Next.js 16 で削除されました:
- AMP サポート — 完全に削除されました。標準のページに移行してください。
next lintコマンド — ESLint または Biome を直接使用してください。serverRuntimeConfigとpublicRuntimeConfig— 代わりに環境変数を使用してください。experimental.pprフラグ — Cache Components に発展しました。"use cache"ディレクティブを使用してください。- 自動的な
scroll-behavior: smooth— 必要に応じて手動で追加してください。 - Node.js 18 のサポート — 最小バージョンは 20.9+ になりました。
移行:
- AMP:AMP ページを標準のページに変換するか、別途 AMP を実装してください。
- Lint:
npx eslint .またはnpx biome lint .を直接実行してください。 - 設定:
serverRuntimeConfigをprocess.env.VARIABLEに置き換えてください。 - PPR:
experimental.pprから"use cache"ディレクティブに移行してください(Cache Components セクションを参照)。
5. バージョン要件(破壊的変更)
Next.js 16 の要件:
- Node.js:20.9 以上(Node.js 18 はサポート対象外になりました)
- TypeScript:5.1 以上(TypeScript を使用する場合)
- React:19.2 以上(Next.js 16 とともに自動的にインストールされます)
- ブラウザー:Chrome 111 以上、Safari 16.4 以上、Firefox 109 以上、Edge 111 以上
バージョンの確認:
node --version # Should be 20.9+
npm --version # Should be 10+
npx next --version # Should be 16.0.0+
Node.js のアップグレード:
# Using nvm
nvm install 20
nvm use 20
nvm alias default 20
# Using Homebrew (macOS)
brew install node@20
# Using apt (Ubuntu/Debian)
sudo apt update
sudo apt install nodejs npm
6. 画像のデフォルト設定の変更(破壊的変更)
Next.js 16 では next/image のデフォルト設定が変更されました:
| 設定 | Next.js 15 | Next.js 16 |
|---|---|---|
| TTL(キャッシュ期間) | 60 秒 | 4 時間 |
| imageSizes | [16, 32, 48, 64, 96, 128, 256, 384] | [640, 750, 828, 1080, 1200](削減) |
| qualities | [75, 90, 100] | [75](単一の品質) |
影響:
- 画像のキャッシュ期間が長くなります(60 秒から 4 時間に延長)
- 生成される画像サイズが減ります(ビルドが小さくなりますが、サイズの刻みが粗くなります)
- 複数の品質ではなく、単一の品質(75)で生成されます
デフォルト設定の上書き(必要な場合):
// next.config.ts
import type { NextConfig } from 'next'
const config: NextConfig = {
images: {
minimumCacheTTL: 60, // Revert to 60 seconds
deviceSizes: [640, 750, 828, 1080, 1200, 1920], // Add larger sizes
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // Restore old sizes
formats: ['image/webp'], // Default
},
}
export default config
テンプレート:templates/image-optimization.tsx を参照してください
キャッシュコンポーネントとキャッシュ API
Next.js 16 の新機能:キャッシュコンポーネントでは、"use cache" ディレクティブによるオプトイン方式のキャッシュが導入され、Next.js 15 の暗黙的なキャッシュが置き換えられます。
1. 概要
変更点:
- Next.js 15:暗黙的なキャッシュ(すべてのサーバーコンポーネントがデフォルトでキャッシュされます)
- Next.js 16:
"use cache"ディレクティブによるオプトイン方式のキャッシュ
変更の理由:明示的なキャッシュにより、開発者がより細かく制御でき、キャッシュの動作が予測しやすくなります。
重要なキャッシュのデフォルト設定(コミュニティ提供):
| 機能 | Next.js 14 | Next.js 15/16 |
|---|---|---|
| fetch() リクエスト | デフォルトでキャッシュされます | デフォルトでキャッシュされません |
| ルーターキャッシュ(動的ページ) | クライアントでキャッシュされます | デフォルトでキャッシュされません |
| ルーターキャッシュ(静的ページ) | キャッシュされます | 引き続きキャッシュされます |
| ルートハンドラー(GET) | キャッシュされます | デフォルトで動的です |
ベストプラクティス:Next.js 16 では、デフォルトで動的にします。予期しないキャッシュヒットのデバッグを避けるため、キャッシュなしで始め、効果がある箇所に追加してください。必ず本番ビルドでテストしてください。開発サーバーの動作は異なります。
キャッシュコンポーネントでできること:
- コンポーネント単位のキャッシュ(ページ全体ではなく、特定のコンポーネントをキャッシュ)
- 関数単位のキャッシュ(計算コストの高い処理をキャッシュ)
- ページ単位のキャッシュ(ページ全体を選択的にキャッシュ)
- 部分的プリレンダリング(PPR) — 静的な部分をキャッシュし、動的な部分はリクエスト時にレンダリング
2. "use cache" ディレクティブ
構文:サーバーコンポーネント、関数、またはルートハンドラーの先頭に "use cache" を追加します。
コンポーネント単位のキャッシュ:
// app/components/expensive-component.tsx
'use cache'
export async function ExpensiveComponent() {
const data = await fetch('https://api.example.com/data')
const json = await data.json()
return (
<div>
<h1>{json.title}</h1>
<p>{json.description}</p>
</div>
)
}
関数単位のキャッシュ:
// lib/data.ts
'use cache'
export async function getExpensiveData(id: string) {
const response = await fetch(`https://api.example.com/items/${id}`)
return response.json()
}
// Usage in component
import { getExpensiveData } from '@/lib/data'
export async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const product = await getExpensiveData(id) // Cached
return <div>{product.name}</div>
}
ページ単位のキャッシュ:
// app/blog/[slug]/page.tsx
'use cache'
export async function generateStaticParams() {
const posts = await fetch('https://api.example.com/posts').then(r => r.json())
return posts.map((post: { slug: string }) => ({ slug: post.slug }))
}
export default async function BlogPost({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const post = await fetch(`https://api.example.com/posts/${slug}`).then(r => r.json())
return (
<article>
<h1>{post.title}</h1>
<div>{post.content}</div>
</article>
)
}
テンプレート:templates/cache-component-use-cache.tsx を参照してください
3. 部分的プリレンダリング(PPR)
PPR では、ページの静的な部分をキャッシュしながら、動的な部分をリクエスト時にレンダリングできます。
パターン:
// app/dashboard/page.tsx
// Static header (cached)
'use cache'
async function StaticHeader() {
return <header>My App</header>
}
// Dynamic user info (not cached)
async function DynamicUserInfo() {
const cookieStore = await cookies()
const userId = cookieStore.get('userId')?.value
const user = await fetch(`/api/users/${userId}`).then(r => r.json())
return <div>Welcome, {user.name}</div>
}
// Page combines both
export default function Dashboard() {
return (
<div>
<StaticHeader /> {/* Cached */}
<DynamicUserInfo /> {/* Dynamic */}
</div>
)
}
PPR を使用する場面:
- ページに静的コンテンツと動的コンテンツの両方がある
- レイアウト、ヘッダー、フッターをキャッシュしつつ、ユーザー固有のコンテンツをレンダリングしたい
- 高速な初回読み込み(静的部分)とパーソナライズ(動的部分)の両方が必要
リファレンス:references/cache-components-guide.md を参照してください
4. revalidateTag() — 更新された API
破壊的変更:revalidateTag() で、stale-while-revalidate の動作を有効にするには第 2 引数(cacheLife プロファイル)が必要になりました。
変更前(Next.js 15):
import { revalidateTag } from 'next/cache'
export async function updatePost(id: string) {
await fetch(`/api/posts/${id}`, { method: 'PATCH' })
revalidateTag('posts') // ❌ Only one argument in Next.js 15
}
変更後(Next.js 16):
import { revalidateTag } from 'next/cache'
export async function updatePost(id: string) {
await fetch(`/api/posts/${id}`, { method: 'PATCH' })
revalidateTag('posts', 'max') // ✅ Second argument required in Next.js 16
}
組み込みのキャッシュライフプロファイル:
'max'— 最大の古さ(ほとんどのユースケースに推奨)'hours'— 数時間後に古くなります'days'— 数日後に古くなります'weeks'— 数週間後に古くなります'default'— デフォルトのキャッシュ動作
カスタムキャッシュライフプロファイル:
revalidateTag('posts', {
stale: 3600, // Stale after 1 hour (seconds)
revalidate: 86400, // Revalidate every 24 hours (seconds)
expire: false, // Never expire (optional)
})
サーバーアクションでのパターン:
'use server'
import { revalidateTag } from 'next/cache'
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
const content = formData.get('content') as string
await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify({ title, content }),
})
revalidateTag('posts', 'max') // ✅ Revalidate with max staleness
}
テンプレート:templates/revalidate-tag-cache-life.ts を参照してください
5. updateTag() - 新しい API(サーバーアクション専用)
Next.js 16 の新機能:updateTag() はサーバーアクションに読み取り後の書き込みのセマンティクスを提供します。
機能:
- キャッシュを直ちに期限切れにします
- 同じリクエスト内でデータを更新します
- ミューテーションの直後に更新されたデータを表示します(古いデータは表示されません)
revalidateTag() との違い:
revalidateTag():Stale-while-revalidate(古いデータを表示し、バックグラウンドで再検証します)updateTag():即時更新(キャッシュを期限切れにし、同じリクエスト内で最新のデータを取得します)
使用例:フォーム、ユーザー設定、またはユーザーが即時のフィードバックを期待するあらゆるミューテーション。
パターン:
'use server'
import { updateTag } from 'next/cache'
export async function updateUserProfile(formData: FormData) {
const name = formData.get('name') as string
const email = formData.get('email') as string
// Update database
await db.users.update({ name, email })
// Immediately refresh cache (read-your-writes)
updateTag('user-profile')
// User sees updated data immediately (no stale data)
}
使用するタイミング:
updateTag():ユーザー設定、プロフィールの更新、重要なミューテーション(即時フィードバック)revalidateTag():ブログ投稿、商品一覧、重要度の低い更新(バックグラウンドで再検証)
テンプレートを参照:templates/server-action-update-tag.ts
6. refresh() - 新しい API(サーバーアクション専用)
Next.js 16 の新機能:refresh() はキャッシュされていないデータのみを更新します(クライアント側の router.refresh() を補完します)。
使用するタイミング:
- キャッシュされたデータに影響を与えずに動的データを更新する
- サーバー側で
router.refresh()を補完する
パターン:
'use server'
import { refresh } from 'next/cache'
export async function refreshDashboard() {
// Refresh uncached data (e.g., real-time metrics)
refresh()
// Cached data (e.g., static header) remains cached
}
revalidateTag() および updateTag() との違い:
refresh():キャッシュされていないデータのみを更新しますrevalidateTag():特定のタグが付いたデータを再検証します(stale-while-revalidate)updateTag():特定のタグが付いたデータを直ちに期限切れにし、更新します
リファレンスを参照:references/cache-components-guide.md
ルートハンドラー(Next.js 16 の更新)
ルートハンドラーの非同期 Params(破壊的変更)
重要:Next.js 16 のルートハンドラーでは、params と headers() が非同期になりました。
例:
// app/api/posts/[id]/route.ts
import { NextResponse } from 'next/server'
import { headers } from 'next/headers'
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params // ✅ Await params in Next.js 16
const headersList = await headers() // ✅ Await headers in Next.js 16
const post = await db.posts.findUnique({ where: { id } })
return NextResponse.json(post)
}
テンプレートを参照:templates/route-handler-api.ts
Proxy と Middleware の比較
Next.js 16 では middleware.ts に代わって proxy.ts が導入されました。
変更の理由
middleware.ts:Edge ランタイムで実行されます(Node.js API が制限されています)proxy.ts:Node.js ランタイムで実行されます(すべての Node.js API を利用できます)
新しい proxy.ts はネットワーク境界を明示し、より柔軟に対応できるようにします。
移行
変更前(middleware.ts):
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
// Check auth
const token = request.cookies.get('token')
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: '/dashboard/:path*',
}
変更後(proxy.ts):
// proxy.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function proxy(request: NextRequest) {
// Check auth
const token = request.cookies.get('token')
if (!token) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
export const config = {
matcher: '/dashboard/:path*',
}
テンプレートを参照:templates/proxy-migration.ts
リファレンスを参照:references/proxy-vs-middleware.md
Parallel Routes - default.js が必須(破壊的変更)
Next.js 16 の破壊的変更:Parallel Routes では明示的な default.js ファイルが必須になりました。
構成:
app/
├── @modal/
│ ├── login/page.tsx
│ └── default.tsx ← REQUIRED in Next.js 16
├── @feed/
│ ├── trending/page.tsx
│ └── default.tsx ← REQUIRED in Next.js 16
└── layout.tsx
デフォルトファイル(必須):
// app/@modal/default.tsx
export default function ModalDefault() {
return null // or <Skeleton /> or redirect
}
必須となった理由:Next.js 16 ではソフトナビゲーションの処理方法が変更されました。default.js がない場合、クライアント側のナビゲーション中に一致しないスロットでエラーが発生します。
高度なエッジケース(コミュニティからの情報):
default.js ファイルがあっても、Parallel Routes を含むルートにハードナビゲーションしたり、再読み込みしたりすると、404 エラーが返されることがあります。回避策として、キャッチオールルートを追加します。
回避策:
// app/@modal/[...catchAll]/page.tsx
export default function CatchAll() {
return null;
}
// OR use catch-all in default.tsx
// app/@modal/default.tsx
export default function ModalDefault({ params }: { params: { catchAll?: string[] } }) {
return null; // Handles all unmatched routes
}
テンプレートを参照:templates/parallel-routes-with-default.tsx
React 19.2 の機能
Next.js 16 は React 19.2 と統合されており、React Canary の新機能が含まれています。
1. View Transitions
使用例:ページ遷移間を滑らかにアニメーション表示します。
'use client'
import { useRouter } from 'next/navigation'
import { startTransition } from 'react'
export function NavigationLink({ href, children }: { href: string; children: React.ReactNode }) {
const router = useRouter()
function handleClick(e: React.MouseEvent) {
e.preventDefault()
// Wrap navigation in startTransition for View Transitions
startTransition(() => {
router.push(href)
})
}
return <a href={href} onClick={handleClick}>{children}</a>
}
CSS View Transitions API を使用する場合:
/* app/globals.css */
@view-transition {
navigation: auto;
}
/* Animate elements with view-transition-name */
.page-title {
view-transition-name: page-title;
}
テンプレートを参照:templates/view-transitions-react-19.tsx
2. useEffectEvent()(実験的機能)
使用例:リアクティブではないロジックを useEffect から切り離します。
'use client'
import { useEffect, experimental_useEffectEvent as useEffectEvent } from 'react'
export function ChatRoom({ roomId }: { roomId: string }) {
const onConnected = useEffectEvent(() => {
console.log('Connected to room:', roomId)
})
useEffect(() => {
const connection = connectToRoom(roomId)
onConnected() // Non-reactive callback
return () => connection.disconnect()
}, [roomId]) // Only re-run when roomId changes
return <div>Chat Room {roomId}</div>
}
使用する理由:コールバックの依存関係が変わったときに、useEffect が不要に再実行されるのを防ぎます。
3. React Compiler(安定版)
使用例:useMemo や useCallback を使わずに自動でメモ化します。
next.config.ts で有効にする:
import type { NextConfig } from 'next'
const config: NextConfig = {
experimental: {
reactCompiler: true,
},
}
export default config
プラグインをインストールする:
npm install babel-plugin-react-compiler
例(手動でメモ化する必要はありません):
'use client'
export function ExpensiveList({ items }: { items: string[] }) {
// React Compiler automatically memoizes this
const filteredItems = items.filter(item => item.length > 3)
return (
<ul>
{filteredItems.map(item => (
<li key={item}>{item}</li>
))}
</ul>
)
}
リファレンスを参照:references/react-19-integration.md
Turbopack(Next.js 16 で安定版)
新機能:Turbopack が Next.js 16 のデフォルトのバンドラーになりました。
パフォーマンスの向上:
- 本番ビルドが 2~5 倍高速化
- Fast Refresh が最大 10 倍高速化
無効化(必要な場合):
npm run build -- --webpack
ファイルシステムキャッシュを有効化(実験的):
// next.config.ts
import type { NextConfig } from 'next'
const config: NextConfig = {
experimental: {
turbopack: {
fileSystemCaching: true, // Beta: Persist cache between runs
},
},
}
export default config
Turbopack の本番環境での制限事項(Next.js 16.1 時点)
既知の問題:
1. Prisma との互換性
Turbopack での本番ビルドは Prisma ORM(v6.5.0 以降)で失敗します。エラー:「path 引数の型は string である必要があります。」
回避策:
# Use webpack for production builds
npm run build -- --webpack
または、next.config.ts に記述します:
const config: NextConfig = {
experimental: {
turbo: false, // Disable Turbopack for production
},
};
2. ソースマップによるセキュリティリスク
Turbopack は現在、ブラウザー向けの本番ソースマップを常に生成するため、本番環境へのデプロイ時にソースコードが公開されます。
回避策:
// next.config.ts
const config: NextConfig = {
productionBrowserSourceMaps: false, // Disable source maps
};
または、デプロイ時に .map ファイルを除外します:
# .vercelignore or similar
*.map
3. 外部モジュールのハッシュ不一致(モノレポ)
node_modules の構成が異なる場合(pnpm、yarn ワークスペース、モノレポなど)、Turbopack が生成する外部モジュールへの参照のハッシュが一致しないことがあります。その結果、本番ビルドで「モジュールが見つかりません」エラーが発生します。
症状:
- ローカルではビルドに成功するが、CI/CD では失敗する
- バンドルされた参照と実際のモジュールファイルとの間でハッシュが一致しない
回避策:
// next.config.ts
const config: NextConfig = {
experimental: {
serverExternalPackages: ['package-name'], // Explicitly externalize packages
},
};
4. バンドルサイズの違い(コミュニティからの報告)
Turbopack でビルドしたバンドルサイズは、webpack でのビルドと異なる場合があります。これは想定どおりの動作であり、Turbopack の成熟に伴って最適化が進められています。
よくあるエラーと解決策
1. エラー:params は Promise です
エラー:
Type 'Promise<{ id: string }>' is not assignable to type '{ id: string }'
原因:Next.js 16 では params が非同期に変更されました。
解決策:params を await します:
// ❌ Before
export default function Page({ params }: { params: { id: string } }) {
const id = params.id
}
// ✅ After
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
}
2. エラー:searchParams は Promise です
エラー:
Property 'query' does not exist on type 'Promise<{ query: string }>'
原因:Next.js 16 では searchParams が非同期になりました。
解決策:
// ❌ Before
export default function Page({ searchParams }: { searchParams: { query: string } }) {
const query = searchParams.query
}
// ✅ After
export default async function Page({ searchParams }: { searchParams: Promise<{ query: string }> }) {
const { query } = await searchParams
}
3. エラー:cookies() には await が必要です
エラー:
'cookies' implicitly has return type 'any'
原因:Next.js 16 では cookies() が非同期になりました。
解決策:
// ❌ Before
import { cookies } from 'next/headers'
export function MyComponent() {
const cookieStore = cookies()
}
// ✅ After
import { cookies } from 'next/headers'
export async function MyComponent() {
const cookieStore = await cookies()
}
4. エラー:並列ルートに default.js がありません
エラー:
Error: Parallel route @modal/login was matched but no default.js was found
原因:Next.js 16 では、すべての並列ルートに default.js が必要です。
解決策:default.tsx ファイルを追加します:
// app/@modal/default.tsx
export default function ModalDefault() {
return null
}
5. エラー:revalidateTag() には 2 つの引数が必要です
エラー:
Expected 2 arguments, but got 1
原因:Next.js 16 では、revalidateTag() に cacheLife 引数が必要になりました。
解決策:
// ❌ Before
revalidateTag('posts')
// ✅ After
revalidateTag('posts', 'max')
6. エラー:Server Component では React フックを使用できません
エラー:
You're importing a component that needs useState. It only works in a Client Component
原因:Server Component で React フックを使用しています。
解決策:'use client' ディレクティブを追加します:
// ✅ Add 'use client' at the top
'use client'
import { useState } from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
7. エラー:middleware.ts は非推奨です
警告:
Warning: middleware.ts is deprecated. Use proxy.ts instead.
解決策:proxy.ts に移行します:
// Rename: middleware.ts → proxy.ts
// Rename function: middleware → proxy
export function proxy(request: NextRequest) {
// Same logic
}
8. エラー:Turbopack のビルドに失敗します
エラー:
Error: Failed to compile with Turbopack
原因:Next.js 16 では Turbopack がデフォルトになりました。
解決策:互換性がない場合は Turbopack を無効にします:
npm run build -- --webpack
9. エラー:next/image の src が無効です
エラー:
Invalid src prop (https://example.com/image.jpg) on `next/image`. Hostname "example.com" is not configured under images in your `next.config.js`
解決策:next.config.ts にリモートパターンを追加します:
const config: NextConfig = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'example.com',
},
],
},
}
10. エラー:Server Component を Client Component にインポートできません
エラー:
You're importing a Server Component into a Client Component
解決策:Server Component を子要素として渡します:
// ❌ Wrong
'use client'
import { ServerComponent } from './server-component' // Error
export function ClientComponent() {
return <ServerComponent />
}
// ✅ Correct
'use client'
export function ClientComponent({ children }: { children: React.ReactNode }) {
return <div>{children}</div>
}
// Usage
<ClientComponent>
<ServerComponent /> {/* Pass as children */}
</ClientComponent>
11. エラー:generateStaticParams が機能しません
原因:generateStaticParams は静的生成(export const dynamic = 'force-static')でのみ機能します。
解決策:
export const dynamic = 'force-static'
export async function generateStaticParams() {
const posts = await fetch('/api/posts').then(r => r.json())
return posts.map((post: { id: string }) => ({ id: post.id }))
}
12. エラー:fetch() がキャッシュされません
原因:Next.js 16 では "use cache" ディレクティブによるオプトイン方式のキャッシュが使用されます。
解決策:コンポーネントまたは関数に "use cache" を追加します:
'use cache'
export async function getPosts() {
const response = await fetch('/api/posts')
return response.json()
}
13. エラー:Route Groups とのルートの競合
エラー:
Error: Conflicting routes: /about and /(marketing)/about
原因:Route Groups によって同じ URL パスが作成されています。
解決策:Route Groups が競合しないようにしてください。
app/
├── (marketing)/about/page.tsx → /about
└── (shop)/about/page.tsx → ERROR: Duplicate /about
# Fix: Use different routes
app/
├── (marketing)/about/page.tsx → /about
└── (shop)/store-info/page.tsx → /store-info
14. エラー:メタデータが更新されない
原因:generateMetadata() を使わずに動的メタデータを使用しています。
解決策:動的ページでは generateMetadata() を使用してください。
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
const { id } = await params
const post = await fetch(`/api/posts/${id}`).then(r => r.json())
return {
title: post.title,
description: post.excerpt,
}
}
15. エラー:next/font のフォントが読み込まれない
原因:フォント変数が HTML 要素に適用されていません。
解決策:フォント変数を <html> または <body> に適用してください。
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' })
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html className={inter.variable}> {/* ✅ Apply variable */}
<body>{children}</body>
</html>
)
}
16. エラー:ブラウザーで環境変数を使用できない
原因:サーバー専用の環境変数はブラウザーに公開されません。
解決策:クライアント側からアクセスできるように、変数名に NEXT_PUBLIC_ を付けてください。
# .env
SECRET_KEY=abc123 # Server-only
NEXT_PUBLIC_API_URL=https://api # Available in browser
// Server Component (both work)
const secret = process.env.SECRET_KEY
const apiUrl = process.env.NEXT_PUBLIC_API_URL
// Client Component (only public vars work)
const apiUrl = process.env.NEXT_PUBLIC_API_URL
17. エラー:Server Action が見つからない
エラー:
Error: Could not find Server Action
原因:'use server' ディレクティブがありません。
解決策:'use server' を追加してください。
// ❌ Before
export async function createPost(formData: FormData) {
await db.posts.create({ ... })
}
// ✅ After
'use server'
export async function createPost(formData: FormData) {
await db.posts.create({ ... })
}
18. エラー:TypeScript のパスエイリアスが機能しない
原因:tsconfig.json の baseUrl または paths の設定が正しくありません。
解決策:正しく設定してください。
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./*"],
"@/components/*": ["./app/components/*"]
}
}
}
参考資料を参照:references/top-errors.md
19. エラー:複数のリダイレクトによってクライアント側のナビゲーションが抑制される
エラー:Throttling navigation to prevent the browser from hanging
出典:GitHub Issue #87245
原因:proxy.ts(または middleware.ts)がクエリパラメーターを追加するためにリダイレクトし、さらに Server Component も異なるクエリパラメーターを追加するために redirect() を呼び出すと、本番ビルドでは <Link> によるクライアント側のナビゲーションが失敗します。これは Next.js 14 から 16 への回帰です。
症状:
next dev(開発モード)では動作する- URL に直接アクセスすると動作する(ページ全体を読み込み)
- 本番ビルドで
<Link>によるクライアント側のナビゲーションを行うと失敗する - プリフェッチによってリダイレクトが無限に繰り返される
解決策:リダイレクト処理を含むページに移動するリンクでは、プリフェッチを無効にしてください。
// ✅ Workaround: Disable prefetch
<Link href="/my-route" prefetch={false}>
Navigate
</Link>
20. エラー:i18n の動的セグメントで Cache Components が失敗する
エラー:generateStaticParams があるにもかかわらず、ルートが動的になる
出典:GitHub Issue #86870
原因:国際化(i18n)フレームワーク(intlayer、next-intl、lingui など)を使用している場合、Cache Components("use cache" ディレクティブ)は動的セグメントで機能しません。レイアウトレベルで generateStaticParams を指定していても、params にアクセスするとルートが動的になります。
発生する理由:すべての i18n フレームワークでは、ロケールを取得するために params へのアクセスが必要です。Next.js 16 では params へのアクセスは非同期呼び出しであり、ページ全体がキャッシュの対象外になります。
解決策:各動的セグメントのレベルに generateStaticParams を追加してください。
// app/[locale]/[id]/page.tsx
export async function generateStaticParams() {
return [
{ locale: 'en', id: '1' },
{ locale: 'en', id: '2' },
// ... all combinations
];
}
'use cache'
export default async function Page({ params }: Props) {
// Now caching works
}
補足情報:コンパイル時に [locale] 動的セグメントが _next などの無効な値を受け取るため、i18n プロバイダーの初期化時に RangeError: Incorrect locale information provided が発生します。
21. エラー:Server Components でカスタムエラークラスの instanceof が失敗する
エラー:instanceof CustomError は CustomError であるにもかかわらず false を返す
出典:GitHub Issue #87614
原因:Server Components でモジュールが重複すると、カスタムエラークラスが 2 回読み込まれ、異なるプロトタイプが作成されます。
解決策:instanceof の代わりに error.name または error.constructor.name を使用してください。
// ❌ Wrong: instanceof doesn't work
try {
throw new CustomError('Test error');
} catch (error) {
if (error instanceof CustomError) { // ❌ false
// Never reached
}
}
// ✅ Correct: Use error.name
try {
throw new CustomError('Test error');
} catch (error) {
if (error instanceof Error && error.name === 'CustomError') { // ✅ true
// Handle CustomError
}
}
// ✅ Alternative: Use constructor.name
if (error.constructor.name === 'CustomError') {
// Handle CustomError
}
22. エラー:TypeScript が Client Components に渡されるシリアライズ不可能な props を検出しない
エラー:関数/クラスインスタンスを Client Components に渡すとランタイムエラーが発生します ソース:GitHub Issue #86748
原因:Next.js の TypeScript プラグインは、Server Components から Client Components に渡されるシリアライズ不可能な props を検出しません。そのため、コンパイル時に検出されないランタイムエラーが発生します。
発生する理由:Server/Client 境界を越えられるのは、シリアライズ可能なデータ(JSON 互換)のみです。関数、クラスインスタンス、Symbol はシリアライズできません。
解決策:シリアライズ可能な props のみを渡します。
// ❌ Wrong: Function not serializable
const user = {
name: 'John',
getProfile: () => console.log('profile'), // ❌ Not serializable
};
<ClientComponent user={user} />
// ✅ Correct: Only serializable props
interface SerializableUser {
name: string;
email: string;
// No functions, no class instances, no Symbols
}
// ✅ Alternative: Create functions in Client Component
'use client';
export default function ClientComponent({ user }: { user: { name: string } }) {
const getProfile = () => console.log('profile'); // Define in client
return <div onClick={getProfile}>{user.name}</div>;
}
ランタイム検証:
import { z } from 'zod';
const UserSchema = z.object({
name: z.string(),
email: z.string(),
});
type User = z.infer<typeof UserSchema>;
23. エラー:Turbopack の本番ビルドが Prisma で失敗する
エラー:The 'path' argument must be of type string
ソース:GitHub Discussion #77721
原因:Turbopack の本番ビルドは Prisma ORM(v6.5.0+)で失敗します。
解決策:本番ビルドでは webpack を使用します。
npm run build -- --webpack
または、設定で Turbopack を無効にします。
// next.config.ts
const config: NextConfig = {
experimental: {
turbo: false,
},
};
24. エラー:Turbopack がソースマップ経由でソースコードを公開する
エラー:本番ビルドでソースコードが見える ソース:GitHub Discussion #77721
原因:Turbopack は常にブラウザー向けの本番ソースマップをビルドするため、ソースコードが公開されます。
解決策:本番ソースマップを無効にします。
// next.config.ts
const config: NextConfig = {
productionBrowserSourceMaps: false,
};
または、デプロイ時に .map ファイルを除外します。
# .vercelignore
*.map
25. エラー:本番環境でモジュールが見つからない(Turbopack モノレポ)
エラー:ローカルビルドが成功しているにもかかわらず、本番環境で Module not found が発生する
ソース:GitHub Issue #87737
原因:Turbopack はハッシュ付きの外部モジュール参照を生成しますが、node_modules の構造が異なる場合(pnpm、yarn workspaces、モノレポ)、ハッシュが一致しません。
症状:
- ローカルではビルドが成功しますが、CI/CD では失敗します
- バンドルされた参照と実際のモジュールファイルとの間でハッシュが一致しません
解決策:パッケージを明示的に外部化します。
// next.config.ts
const config: NextConfig = {
experimental: {
serverExternalPackages: ['package-name'],
},
};
参考:references/top-errors.md
テンプレートとリソース
Next.js 16 固有のテンプレート(templates/ 内):
app-router-async-params.tsx- 非同期 params への移行パターンparallel-routes-with-default.tsx- 必須の default.js ファイルcache-component-use-cache.tsx-"use cache"を使った Cache Componentsrevalidate-tag-cache-life.ts- cacheLife を使った更新版revalidateTag()server-action-update-tag.ts- read-your-writes 用のupdateTag()proxy-migration.ts- middleware.ts から proxy.ts への移行view-transitions-react-19.tsx- React 19.2 の View Transitionsnext.config.ts- Next.js 16 の設定
同梱リファレンス(references/ 内):
next-16-migration-guide.md- Next.js 15→16 完全移行ガイドcache-components-guide.md- Cache Components の詳細解説proxy-vs-middleware.md- Proxy.ts と middleware.ts の比較async-route-params.md- 非同期 params の破壊的変更の詳細react-19-integration.md- Next.js 16 における React 19.2 の機能top-errors.md- 解決策付きの一般的なエラー 18 件以上
外部ドキュメント:
- Next.js 16 ブログ:https://nextjs.org/blog/next-16
- Next.js ドキュメント:https://nextjs.org/docs
- Context7 MCP:最新のリファレンスは
/websites/nextjs
バージョン互換性
| パッケージ | 最小バージョン | 推奨 |
|---|---|---|
| Next.js | 16.0.0 | 16.1.1+ |
| React | 19.2.0 | 19.2.3+ |
| Node.js | 20.9.0 | 20.9.0+ |
| TypeScript | 5.1.0 | 5.7.0+ |
| Turbopack | (組み込み) | 安定版 |
バージョンの確認:
./scripts/check-versions.sh
トークン効率
推定トークン削減率:65~70%
スキルなしの場合(ドキュメントを参照して手動で設定):
- Next.js 16 移行ガイドを読む:約5kトークン
- App Router のドキュメントを読む:約8kトークン
- Server Actions のドキュメントを読む:約4kトークン
- Metadata API のドキュメントを読む:約3kトークン
- 試行錯誤による修正:約8kトークン
- 合計:約28kトークン
スキルを使用する場合:
- スキルを読み込む:約8kトークン
- テンプレートを使用する:約2kトークン
- 合計:約10kトークン
- 削減量:約18kトークン(約64%)
防止できるエラー:文書化された25件のエラーを100%防止
メンテナンス
最終確認日:2026-01-21 スキルのバージョン:3.1.0 変更内容:新たに7件のエラー(ナビゲーションのスロットリング、i18n のキャッシュ、Turbopack の制限、instanceof の失敗、シリアライズできない props)を追加しました。非同期 params の codemod の制限、キャッシュのデフォルト設定、並列ルートのエッジケースについて説明を拡充しました。
次回のレビュー:2026-04-21(四半期ごと) メンテナー:Jezweb | [email protected] リポジトリ:https://github.com/jezweb/claude-skills
更新の契機:
- Next.js のメジャー/マイナーリリース
- React のメジャーリリース
- API の破壊的変更
- 新しい Turbopack の機能
バージョンの確認:
cd skills/nextjs
./scripts/check-versions.sh
SKILL.md の終わり