jpskill.com
🛠️ 開発・MCP コミュニティ

nextjs-15-patterns

Next.js 15 App Router patterns and best practices.

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o nextjs-15-patterns.zip https://jpskill.com/download/17461.zip && unzip -o nextjs-15-patterns.zip && rm nextjs-15-patterns.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/17461.zip -OutFile "$d\nextjs-15-patterns.zip"; Expand-Archive "$d\nextjs-15-patterns.zip" -DestinationPath $d -Force; ri "$d\nextjs-15-patterns.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して nextjs-15-patterns.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → nextjs-15-patterns フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
4

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Next.js 15 のパターン

Server Components と Client Components

デフォルト: Server Components

// app/users/page.tsx - Server Component (デフォルト)
export default async function UsersPage() {
  const users = await getUsers(); // 直接 DB にアクセス
  return <UserList users={users} />;
}

Client Components (必要な場合)

// components/counter.tsx
'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

Server Actions

// actions/user-actions.ts
'use server';

import { revalidatePath } from 'next/cache';
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

export async function createUser(formData: FormData) {
  const validated = CreateUserSchema.safeParse({
    name: formData.get('name'),
    email: formData.get('email'),
  });

  if (!validated.success) {
    return { error: validated.error.flatten() };
  }

  const user = await db.insert(users).values(validated.data).returning();
  revalidatePath('/users');
  return { data: user };
}

データフェッチ

Server Components 内で

// 直接 async/await - useEffect は不要
async function UserProfile({ id }: { id: string }) {
  const user = await getUser(id);
  if (!user) notFound();
  return <Profile user={user} />;
}

ローディング状態を使用する

// app/users/loading.tsx
export default function Loading() {
  return <UserListSkeleton />;
}

エラー処理を使用する

// app/users/error.tsx
'use client';

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <h2>問題が発生しました</h2>
      <button onClick={reset}>再試行</button>
    </div>
  );
}

Route Handlers (API)

// app/api/users/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  const users = await getUsers();
  return NextResponse.json(users);
}

export async function POST(request: Request) {
  const body = await request.json();
  const user = await createUser(body);
  return NextResponse.json(user, { status: 201 });
}

Metadata

// app/users/[id]/page.tsx
import { Metadata } from 'next';

export async function generateMetadata({
  params,
}: {
  params: { id: string };
}): Promise<Metadata> {
  const user = await getUser(params.id);
  return {
    title: user?.name ?? 'User',
    description: `Profile for ${user?.name}`,
  };
}

Parallel Routes

app/
├── @modal/
│   └── (.)photo/[id]/page.tsx  # Intercepted modal
├── layout.tsx
└── page.tsx

ベストプラクティス

  1. Server Components を優先する - 'use client' は必要な場合にのみ使用します
  2. データフェッチを同じ場所に配置する - データが使用される場所でフェッチします
  3. Server Actions を使用する - API ルートではなく、変更に使用します
  4. Suspense でストリーミングする - プログレッシブなローディングに使用します
  5. すべての入力を検証する - Server Actions に Zod を使用します
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Next.js 15 Patterns

Server vs Client Components

Default: Server Components

// app/users/page.tsx - Server Component (default)
export default async function UsersPage() {
  const users = await getUsers(); // Direct DB access
  return <UserList users={users} />;
}

Client Components (when needed)

// components/counter.tsx
'use client';

import { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

Server Actions

// actions/user-actions.ts
'use server';

import { revalidatePath } from 'next/cache';
import { z } from 'zod';

const CreateUserSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
});

export async function createUser(formData: FormData) {
  const validated = CreateUserSchema.safeParse({
    name: formData.get('name'),
    email: formData.get('email'),
  });

  if (!validated.success) {
    return { error: validated.error.flatten() };
  }

  const user = await db.insert(users).values(validated.data).returning();
  revalidatePath('/users');
  return { data: user };
}

Data Fetching

In Server Components

// Direct async/await - no useEffect needed
async function UserProfile({ id }: { id: string }) {
  const user = await getUser(id);
  if (!user) notFound();
  return <Profile user={user} />;
}

With Loading States

// app/users/loading.tsx
export default function Loading() {
  return <UserListSkeleton />;
}

With Error Handling

// app/users/error.tsx
'use client';

export default function Error({
  error,
  reset,
}: {
  error: Error;
  reset: () => void;
}) {
  return (
    <div>
      <h2>Something went wrong</h2>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

Route Handlers (API)

// app/api/users/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  const users = await getUsers();
  return NextResponse.json(users);
}

export async function POST(request: Request) {
  const body = await request.json();
  const user = await createUser(body);
  return NextResponse.json(user, { status: 201 });
}

Metadata

// app/users/[id]/page.tsx
import { Metadata } from 'next';

export async function generateMetadata({
  params,
}: {
  params: { id: string };
}): Promise<Metadata> {
  const user = await getUser(params.id);
  return {
    title: user?.name ?? 'User',
    description: `Profile for ${user?.name}`,
  };
}

Parallel Routes

app/
├── @modal/
│   └── (.)photo/[id]/page.tsx  # Intercepted modal
├── layout.tsx
└── page.tsx

Best Practices

  1. Prefer Server Components - Only use 'use client' when needed
  2. Colocate data fetching - Fetch where data is used
  3. Use Server Actions - For mutations, not API routes
  4. Streaming with Suspense - For progressive loading
  5. Validate all inputs - Use Zod for server actions

同梱ファイル

※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。