frontend-nextjs-app-router
Next.js App Router を利用した開発で、/app ディレクトリ内のページ作成、動的なルーティング設定、レイアウト構築、サーバー/クライアントコンポーネント最適化、ERPロール別ページ構築などを効率的に行うSkill。
📜 元の英語説明(参考)
Use when working with Next.js App Router tasks - creating pages in /app/, setting up dynamic routes ([id]/page.tsx), implementing nested layouts/templates (layout.tsx), optimizing Server/Client components, or building ERP role-based pages (admin/teacher/student dashboards). Auto-use for all /app/ directory operations, dynamic routing, and App Router-specific features.
🇯🇵 日本人クリエイター向け解説
Next.js App Router を利用した開発で、/app ディレクトリ内のページ作成、動的なルーティング設定、レイアウト構築、サーバー/クライアントコンポーネント最適化、ERPロール別ページ構築などを効率的に行うSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o frontend-nextjs-app-router.zip https://jpskill.com/download/17384.zip && unzip -o frontend-nextjs-app-router.zip && rm frontend-nextjs-app-router.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/17384.zip -OutFile "$d\frontend-nextjs-app-router.zip"; Expand-Archive "$d\frontend-nextjs-app-router.zip" -DestinationPath $d -Force; ri "$d\frontend-nextjs-app-router.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
frontend-nextjs-app-router.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
frontend-nextjs-app-routerフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 2
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
Next.js App Router エキスパート
概要
Next.js App Router 開発に関する専門的なガイダンスです。ページ作成、動的ルーティング、ネストされたレイアウト、サーバー/クライアントコンポーネントの最適化、ERP ロールベースのダッシュボードなどが含まれます。
主要な機能
1. ページ作成 (/app/.../page.tsx)
ルール:
- デフォルトでサーバーコンポーネントを使用する(
'use client'ディレクティブは不要) fetch()または ORM クエリで非同期データフェッチを直接行う- 初回データロードに
useEffectは使用しない - ローディング状態には
Suspenseバウンダリを使用する - SEO メタデータは
generateMetadata()を介して設定する
テンプレート:
// app/dashboard/page.tsx
import { Suspense } from 'react';
import { TaskList } from '@/components/TaskList';
import { TaskListSkeleton } from '@/components/TaskListSkeleton';
export const metadata = {
title: 'Dashboard',
description: 'Your task management dashboard',
};
export default async function DashboardPage() {
const tasks = await fetchTasks();
return (
<main className="p-4">
<h1>Dashboard</h1>
<Suspense fallback={<TaskListSkeleton />}>
<TaskList initialTasks={tasks} />
</Suspense>
</main>
);
}
2. 動的ルート ([slug]/page.tsx)
使用場面:
- 学生プロフィール:
app/students/[studentId]/page.tsx - タスク詳細:
app/tasks/[taskId]/page.tsx - コースページ:
app/courses/[courseId]/page.tsx
ルール:
paramsプロパティからパラメータを抽出する(読み取り専用)- SEO には
generateMetadata()を使用する - 404 エラーは
not-found.tsxで処理する
テンプレート:
// app/students/[studentId]/page.tsx
import { notFound } from 'next/navigation';
type Params = Promise<{ studentId: string }>;
export async function generateMetadata({ params }: { params: Params }) {
const { studentId } = await params;
const student = await getStudent(studentId);
if (!student) return { title: 'Student Not Found' };
return {
title: `${student.name} - Student Profile`,
};
}
export default async function StudentProfile({ params }: { params: Params }) {
const { studentId } = await params;
const student = await getStudent(studentId);
if (!student) notFound();
return <StudentProfileView student={student} />;
}
3. 並列ルート (@folder)
使用場面:
- ダッシュボードのバリアント:
app/dashboard@(admin|teacher)/page.tsx - 分割レイアウト:
app/settings@(user|organization)/layout.tsx
テンプレート:
// app/dashboard/@admin/page.tsx - 管理者ダッシュボード
export default function AdminDashboard() {
return <AdminPanel />;
}
// app/dashboard/@teacher/page.tsx - 教師ダッシュボード
export default function TeacherDashboard() {
return <TeacherPanel />;
}
4. レイアウトとテンプレート
ルートレイアウト (app/layout.tsx):
import { Providers } from '@/components/Providers';
import './globals.css';
export const metadata = {
title: 'Todo Evolution',
description: 'Task management for education',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
ネストされたレイアウト (app/dashboard/layout.tsx):
import { DashboardNav } from '@/components/DashboardNav';
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-screen">
<DashboardNav />
<main className="flex-1 p-6">{children}</main>
</div>
);
}
テンプレート (app/tasks/template.tsx):
// ナビゲーション時に再実行され、フォームの状態を保持します
export default function TasksTemplate({ children }: { children: React.ReactNode }) {
return (
<div className="bg-gray-50 min-h-screen">
<header className="bg-white shadow">
<h1>Tasks</h1>
</header>
{children}
</div>
);
}
5. サーバー vs クライアントコンポーネント
サーバーコンポーネントの使用場面:
- データフェッチ
- 直接的なデータベースクエリ
- 静的なコンテンツ
- サーバーのみの操作
クライアントコンポーネント ('use client') の使用場面:
- ブラウザ API (
window,localStorage) - イベントハンドラ (
onClick,onSubmit) - React フック (
useState,useEffect) - 状態管理 (Zustand, Redux)
- インタラクティビティ
// サーバーコンポーネント (デフォルト)
export default async function TaskList() {
const tasks = await fetchTasks(); // 直接 DB クエリ
return <div>{tasks.map(/* ... */)}</div>;
}
// クライアントコンポーネント
'use client';
import { useTaskStore } from '@/store/tasks';
export function TaskFilter() {
const { filter, setFilter } = useTaskStore();
return <button onClick={() => setFilter('all')}>All Tasks</button>;
}
6. ERP ロールベースのページ
ロールガード:
// app/admin/page.tsx
import { requireRole } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function AdminPage() {
const session = await getSession();
if (session?.role !== 'admin') {
redirect('/unauthorized');
}
return <AdminDashboard />;
}
KPI ダッシュボード (Recharts):
'use client';
import { BarChart, Bar, XAxis, YAxis, Tooltip } from 'recharts';
export function TaskKPIChart({ data }: { data: TaskStats[] }) {
return (
<BarChart width={600} height={300} data={data}>
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Bar dataKey="completed" fill="#22c55e" />
</BarChart>
);
}
7. エラーとローディング状態
エラーバウンダリ (error.tsx):
'use client';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</div>
);
}
ローディング状態 (loading.tsx):
export default function Loading() {
return <div className="animate-pulse">Loading...</div>;
}
// または Suspense を使用:
export default async function Page() {
return (
<Suspense fallback={<Loading />}>
<Cont 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
Next.js App Router Expert
Overview
Expert guidance for Next.js App Router development including page creation, dynamic routing, nested layouts, Server/Client component optimization, and ERP role-based dashboards.
Core Capabilities
1. Page Creation (/app/.../page.tsx)
Rules:
- Use Server Components by default (no 'use client' directive)
- Async data fetching with
fetch()or ORM queries directly - No
useEffectfor initial data load - Use
Suspenseboundaries for loading states - SEO metadata via
generateMetadata()
Template:
// app/dashboard/page.tsx
import { Suspense } from 'react';
import { TaskList } from '@/components/TaskList';
import { TaskListSkeleton } from '@/components/TaskListSkeleton';
export const metadata = {
title: 'Dashboard',
description: 'Your task management dashboard',
};
export default async function DashboardPage() {
const tasks = await fetchTasks();
return (
<main className="p-4">
<h1>Dashboard</h1>
<Suspense fallback={<TaskListSkeleton />}>
<TaskList initialTasks={tasks} />
</Suspense>
</main>
);
}
2. Dynamic Routes ([slug]/page.tsx)
When to use:
- Student profiles:
app/students/[studentId]/page.tsx - Task details:
app/tasks/[taskId]/page.tsx - Course pages:
app/courses/[courseId]/page.tsx
Rules:
- Extract params from
paramsprop (read-only) - Use
generateMetadata()for SEO - Handle 404 with
not-found.tsx
Template:
// app/students/[studentId]/page.tsx
import { notFound } from 'next/navigation';
type Params = Promise<{ studentId: string }>;
export async function generateMetadata({ params }: { params: Params }) {
const { studentId } = await params;
const student = await getStudent(studentId);
if (!student) return { title: 'Student Not Found' };
return {
title: `${student.name} - Student Profile`,
};
}
export default async function StudentProfile({ params }: { params: Params }) {
const { studentId } = await params;
const student = await getStudent(studentId);
if (!student) notFound();
return <StudentProfileView student={student} />;
}
3. Parallel Routes (@folder)
When to use:
- Dashboard variants:
app/dashboard@(admin|teacher)/page.tsx - Split layouts:
app/settings@(user|organization)/layout.tsx
Template:
// app/dashboard/@admin/page.tsx - Admin dashboard
export default function AdminDashboard() {
return <AdminPanel />;
}
// app/dashboard/@teacher/page.tsx - Teacher dashboard
export default function TeacherDashboard() {
return <TeacherPanel />;
}
4. Layouts & Templates
Root Layout (app/layout.tsx):
import { Providers } from '@/components/Providers';
import './globals.css';
export const metadata = {
title: 'Todo Evolution',
description: 'Task management for education',
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
Nested Layout (app/dashboard/layout.tsx):
import { DashboardNav } from '@/components/DashboardNav';
export default function DashboardLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div className="flex min-h-screen">
<DashboardNav />
<main className="flex-1 p-6">{children}</main>
</div>
);
}
Template (app/tasks/template.tsx):
// Re-executes on navigation, preserves form state
export default function TasksTemplate({ children }: { children: React.ReactNode }) {
return (
<div className="bg-gray-50 min-h-screen">
<header className="bg-white shadow">
<h1>Tasks</h1>
</header>
{children}
</div>
);
}
5. Server vs Client Components
Use Server Components for:
- Data fetching
- Direct database queries
- Static content
- Server-only operations
Use Client Components ('use client') for:
- Browser APIs (
window,localStorage) - Event handlers (
onClick,onSubmit) - React hooks (
useState,useEffect) - State management (Zustand, Redux)
- Interactivity
// Server Component (default)
export default async function TaskList() {
const tasks = await fetchTasks(); // Direct DB query
return <div>{tasks.map(/* ... */)}</div>;
}
// Client Component
'use client';
import { useTaskStore } from '@/store/tasks';
export function TaskFilter() {
const { filter, setFilter } = useTaskStore();
return <button onClick={() => setFilter('all')}>All Tasks</button>;
}
6. ERP Role-Based Pages
Role Guards:
// app/admin/page.tsx
import { requireRole } from '@/lib/auth';
import { redirect } from 'next/navigation';
export default async function AdminPage() {
const session = await getSession();
if (session?.role !== 'admin') {
redirect('/unauthorized');
}
return <AdminDashboard />;
}
KPI Dashboard (Recharts):
'use client';
import { BarChart, Bar, XAxis, YAxis, Tooltip } from 'recharts';
export function TaskKPIChart({ data }: { data: TaskStats[] }) {
return (
<BarChart width={600} height={300} data={data}>
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Bar dataKey="completed" fill="#22c55e" />
</BarChart>
);
}
7. Error & Loading States
Error Boundary (error.tsx):
'use client';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div>
<h2>Something went wrong!</h2>
<button onClick={reset}>Try again</button>
</div>
);
}
Loading State (loading.tsx):
export default function Loading() {
return <div className="animate-pulse">Loading...</div>;
}
// Or with Suspense:
export default async function Page() {
return (
<Suspense fallback={<Loading />}>
<Content />
</Suspense>
);
}
8. shadcn/ui Integration
Installation:
npx shadcn@latest add button card input dialog
Usage in Server Components:
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader } from '@/components/ui/card';
export default async function TaskPage() {
const tasks = await getTasks();
return (
<Card>
<CardHeader>Tasks</CardHeader>
<CardContent>
{tasks.map(task => (
<div key={task.id}>{task.title}</div>
))}
</CardContent>
</Card>
);
}
Workflow Decision Tree
User Request → Analyze → Implementation Path
-
"Dashboard/Admin page banao" → Server Component with
page.tsx→ Async data fetch → Addlayout.tsxif navigation needed -
"Dynamic student profile" → Create
[studentId]/page.tsx→ Extract params → AddgenerateMetadata()→ Createnot-found.tsxif needed -
"Shared layout add karo" → Create
layout.tsxin target folder → Wrap with providers if needed → Maintain children render -
"Form add karo" →
'use client'component → useState for form data → Server Action for submission OR API route -
"KPI charts/Analytics" →
'use client'for Recharts → Server Component parent with data fetch → Pass data as props
Quality Checklist
Before marking task complete:
- [ ] TypeScript strict mode enabled
- [ ] Server Components used by default
- [ ]
'use client'only when necessary - [ ]
generateMetadata()for SEO - [ ] Suspense boundaries for async data
- [ ] Error boundaries (
error.tsx) where needed - [ ] No hydration mismatches
- [ ] Performance optimized (no blocking renders)
- [ ] Mobile-first responsive design
- [ ] Accessible (ARIA labels, keyboard nav)
Common Patterns
Pattern 1: Server Component + Client Component Mix
// Server Component
export default async function Page() {
const tasks = await fetchTasks();
return <TaskList tasks={tasks} />; // Client component for interactivity
}
'use client';
function TaskList({ tasks }: { tasks: Task[] }) {
const [filter, setFilter] = useState('all');
const filtered = tasks.filter(/* ... */);
return <div>{filtered.map(/* ... */)}</div>;
}
Pattern 2: Route Groups for Organization
app/
(marketing)/ # Group: no URL segment
about/page.tsx
contact/page.tsx
(dashboard)/ # Group: no URL segment
layout.tsx
page.tsx
Pattern 3: API Routes (Route Handlers)
// app/api/tasks/route.ts
import { NextResponse } from 'next/server';
export async function GET() {
const tasks = await db.query.tasks.findMany();
return NextResponse.json(tasks);
}
export async function POST(request: Request) {
const body = await request.json();
const task = await createTask(body);
return NextResponse.json(task, { status: 201 });
}
Trigger Examples
- "Dashboard page banao" → Generate
app/dashboard/page.tsxwith server component - "Dynamic student profile route" →
app/students/[studentId]/page.tsxwith params and metadata - "Shared layout add karo" →
app/dashboard/layout.tsxwith children - "Admin panel with charts" → Server component + Client chart component
- "Login page banao" →
'use client'form component + API route - "404 page customize karo" →
app/not-found.tsx - "Error handle karo" →
app/dashboard/error.tsx
References
See references/app-router-patterns.md for advanced patterns and references/api-routes.md for route handler examples.
同梱ファイル
※ ZIPに含まれるファイル一覧。`SKILL.md` 本体に加え、参考資料・サンプル・スクリプトが入っている場合があります。
- 📄 SKILL.md (10,080 bytes)
- 📎 references/app-router-patterns.md (5,220 bytes)