mcpField
N
nextjs

nextjs

github.com/ovachiever開発5665 回インストール49 週間前に更新
リポジトリ

nextjs について

Next.js App Routerを使う開発者向けのスキルです。Next.js 16とReact 19.2の実践パターンを、破壊的変更、キャッシュAPI、移行、エラー対応を中心に解説します。

主な機能

  1. 01Next.js 16への移行ガイド
  2. 02非同期ルートパラメーターの処理
  3. 03Cache ComponentsとキャッシュAPI
  4. 04Proxyと並列ルートの設定
  5. 05一般的なエラーと解決策

活用シーン

  1. 01Next.js 15から16へのプロジェクト移行
  2. 02App Routerのキャッシュ設定
  3. 03並列ルートや非同期パラメーターの問題解決

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ovachiever/droid-tings --skill nextjs

インストール後、Claude Code で/nextjsを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
.claude-plugin/
plugin.json
references/
next-16-migration-guide.md
top-errors.md
scripts/
check-versions.sh
templates/
app-router-async-params.tsx
cache-component-use-cache.tsx
package.json
parallel-routes-with-default.tsx
proxy-migration.ts
route-handler-api.ts
server-actions-form.tsx

詳細

Next.js App Router - 本番環境向けパターン

バージョン: Next.js 16.0.0 React バージョン: 19.2.0 Node.js: 20.9+ 最終検証日: 2025-10-24


目次

  1. このスキルを使用する場面
  2. このスキルを使用しない場面
  3. Next.js 16 の破壊的変更
  4. Cache Components とキャッシュ API
  5. Route Handlers(Next.js 16 の更新)
  6. Proxy と Middleware
  7. Parallel Routes - default.js が必須
  8. React 19.2 の機能
  9. Turbopack(Next.js 16 で安定版)
  10. よくあるエラーと解決策
  11. テンプレートとリソース

このスキルを使用する場面

焦点: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、サイズ、品質)
  • エラーの予防(解決策とともに記載された 18 件以上の Next.js 16 のエラー)

このスキルを使用しない場面

次の用途にはこのスキルを使用しないでください。

  • 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 の連携に使用します(このスキルと組み合わせて使用できます)

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 を実行すると、自動的に移行できます。

テンプレートを参照:templates/app-router-async-params.tsx


2. Middleware から Proxy への移行(破壊的変更)

破壊的変更:Next.js 16 では middleware.ts は非推奨です。代わりに proxy.ts を使用してください。

変更の理由:proxy.ts は Node.js ランタイム(Edge ランタイムではなく)で実行され、ネットワーク境界を明確にします。これにより、エッジミドルウェアとサーバーサイドプロキシの違いがより明確になります。

移行手順:

  1. ファイル名を変更:middleware.ts → proxy.ts
  2. 関数名を変更:middleware → proxy
  3. 設定を更新: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 で削除されました:

  1. AMP サポート - 完全に削除されました。標準ページに移行してください。
  2. next lint コマンド - ESLint または Biome を直接使用してください。
  3. serverRuntimeConfig と publicRuntimeConfig - 代わりに環境変数を使用してください。
  4. experimental.ppr フラグ - Cache Components に進化しました。"use cache" ディレクティブを使用してください。
  5. 自動的な scroll-behavior: smooth - 必要に応じて手動で追加してください。
  6. 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 15Next.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


Cache Components とキャッシュ API

Next.js 16 の新機能:Cache Components は "use cache" ディレクティブによるオプトイン方式のキャッシュを導入し、Next.js 15 の暗黙的なキャッシュに置き換わります。

1. 概要

変更点:

  • Next.js 15:暗黙的なキャッシュ(すべての Server Component がデフォルトでキャッシュされます)
  • Next.js 16:オプトイン方式のキャッシュ("use cache" ディレクティブを使用します)

変更の理由:明示的なキャッシュにより、開発者はより細かく制御でき、キャッシュの動作も予測しやすくなります。

Cache Components でできること:

  • コンポーネント単位のキャッシュ(ページ全体ではなく、特定のコンポーネントをキャッシュします)
  • 関数単位のキャッシュ(コストの高い計算をキャッシュします)
  • ページ単位のキャッシュ(ページ全体を選択的にキャッシュします)
  • Partial Prerendering(PPR) - 静的な部分をキャッシュし、動的な部分をオンデマンドでレンダリングします

2. "use cache" ディレクティブ

構文:Server Component、関数、またはルートハンドラーの先頭に "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. Partial Prerendering(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
}

組み込みの Cache Life プロファイル:

  • 'max' - 最大の古さを許容します(ほとんどのユースケースで推奨)
  • 'hours' - 数時間後に古くなります
  • 'days' - 数日後に古くなります
  • 'weeks' - 数週間後に古くなります
  • 'default' - デフォルトのキャッシュ動作

カスタム Cache Life プロファイル:

revalidateTag('posts', {
  stale: 3600, // Stale after 1 hour (seconds)
  revalidate: 86400, // Revalidate every 24 hours (seconds)
  expire: false, // Never expire (optional)
})

Server Action でのパターン:

'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(Server Action 専用)

Next.js 16 の新機能:updateTag() は Server Action で read-your-writes セマンティクスを提供します。

動作:

  • キャッシュをただちに期限切れにします
  • 同じリクエスト内でデータを更新します
  • ミューテーション直後に更新されたデータを表示します(古いデータは表示されません)

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(Server Action 専用)

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 を参照してください。



Route Handler(Next.js 16 の更新)

Route Handler の非同期 Params(破壊的変更)

重要:Next.js 16 の Route Handler では、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 がない場合、クライアント側のナビゲーション中に一致しないスロットでエラーが発生します。

テンプレート: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

よくあるエラーと解決方法

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. エラー:Parallel Route に default.js がありません

エラー:

Error: Parallel route @modal/login was matched but no default.js was found

原因:Next.js 16 では、すべての Parallel Route に 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 を children として渡します:

// ❌ 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


テンプレートとリソース

Next.js 16 専用テンプレート(templates/ 内):

  • app-router-async-params.tsx - Async params の移行パターン
  • parallel-routes-with-default.tsx - 必須の default.js ファイル
  • cache-component-use-cache.tsx - "use cache" を使用した Cache Components
  • revalidate-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 Transitions
  • next.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 - Async params の破壊的変更の詳細
  • react-19-integration.md - Next.js 16 における React 19.2 の機能
  • top-errors.md - 18 件以上のよくあるエラーと解決策

外部ドキュメント:


バージョン互換性

パッケージ最小バージョン推奨
Next.js16.0.016.0.0+
React19.2.019.2.0+
Node.js20.9.020.9.0+
TypeScript5.1.05.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%)

防止できるエラー:よくある 18 件以上のミスを防止=エラーを 100% 防止


メンテナンス

最終確認日:2025-10-24 次回確認日:2026-01-24(四半期ごと) メンテナー:Jezweb | [email protected] リポジトリ:https://github.com/jezweb/claude-skills

更新の契機:

  • Next.js のメジャー/マイナーリリース
  • React のメジャーリリース
  • API の破壊的変更
  • Turbopack の新機能

バージョン確認:

cd skills/nextjs
./scripts/check-versions.sh

SKILL.md の終わり

コメント