nextjs-app-router
Next.js 16以降のApp Routerアーキテクチャを使ったアプリケーション構築のパターンとコード例を提供します。App Routerを使ったプロジェクト作成、Server ComponentsとClient Components("use client")の実装、フォーム向けServer Actionsの作成、Route Handlers(route.ts)の構築、"use cache"ディレクティブ(cacheLife、cacheTag)によるキャッシュ設定、並列ルート(`@slot`)やインターセプトルートの設定、proxy.tsへの移行、またはlayout.tsx・page.tsx・loading.tsx・error.tsxといったApp Routerのファイル規約を扱う際に使用します。
description の原文を見る
Provides patterns and code examples for building Next.js 16+ applications with App Router architecture. Use when creating projects with App Router, implementing Server Components and Client Components ("use client"), creating Server Actions for forms, building Route Handlers (route.ts), configuring caching with "use cache" directive (cacheLife, cacheTag), setting up parallel routes (`@slot`) or intercepting routes, migrating to proxy.ts, or working with App Router file conventions (layout.tsx, page.tsx, loading.tsx, error.tsx).
SKILL.md 本文
Next.js App Router (Next.js 16+)
Next.js 16+ の App Router アーキテクチャを使用して、モダンな React アプリケーションを構築します。
概要
このスキルは、Server Components (デフォルト) と Client Components ("use client")、ミューテーションとフォーム処理用の Server Actions、API エンドポイント用の Route Handlers、"use cache" ディレクティブによる明示的なキャッシング、パラレルおよびインターセプティングルート、Next.js 16 の async API と proxy.ts のパターンを提供します。
いつ使用するか
以下のユーザーリクエストが含まれる場合に実装します:
- "Next.js 16 プロジェクトを作成する"、"App Router をセットアップする"
- "Server Component"、"Client Component"、"use client"
- "Server Action"、"フォーム送信"、"ミューテーション"
- "Route Handler"、"API エンドポイント"、"route.ts"
- "use cache"、"cacheLife"、"cacheTag"、"revalidation"
- "parallel routes"、"
@slot"、"intercepting routes" - "proxy.ts"、"middleware.ts からの移行"
- "layout.tsx"、"page.tsx"、"loading.tsx"、"error.tsx"、"not-found.tsx"
- "generateMetadata"、"next/image"、"next/font"
クイックリファレンス
| ファイル | 用途 | ディレクティブ | 用途 |
|---|---|---|---|
page.tsx | ルートページ | "use server" | Server Action 関数 |
layout.tsx | 共有レイアウト | "use client" | Client Component 境界 |
loading.tsx | Suspense ローディング | "use cache" | 明示的なキャッシング (Next.js 16) |
error.tsx | エラーバウンダリ | ||
not-found.tsx | 404 ページ | ||
route.ts | API Route Handler | ||
proxy.ts | ルーティング境界 |
説明
新しいプロジェクトを作成する
npx create-next-app@latest my-app --typescript --tailwind --app --turbopack
Server Component
Server Components は App Router のデフォルトです。サーバー上で実行され、async/await を使用できます。
// app/users/page.tsx
async function getUsers() {
const apiUrl = process.env.API_URL;
const res = await fetch(`${apiUrl}/users`);
return res.json();
}
export default async function UsersPage() {
const users = await getUsers();
return <main>{users.map(user => <UserCard key={user.id} user={user} />)}</main>;
}
Client Component
フック、ブラウザ API、またはイベントハンドラーを使用する場合は "use client" を追加します。
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return <button onClick={() => setCount(c => c + 1)}>Count: {count}</button>;
}
Server Action
"use server" ディレクティブを持つ別のファイルにアクションを定義します。
// app/actions.ts
"use server";
import { revalidatePath } from "next/cache";
export async function createUser(formData: FormData) {
const name = formData.get("name") as string;
const email = formData.get("email") as string;
await db.user.create({ data: { name, email } });
revalidatePath("/users");
}
Client Components のフォームで使用します:
"use client";
import { useActionState } from "react";
import { createUser } from "./actions";
export default function UserForm() {
const [state, formAction, pending] = useActionState(createUser, {});
return (
<form action={formAction}>
<input name="name" />
<input name="email" type="email" />
<button type="submit" disabled={pending}>{pending ? "Creating..." : "Create"}</button>
</form>
);
}
Zod バリデーション、楽観的更新、高度なパターンについては references/server-actions.md を参照してください。
キャッシングを構成する
"use cache" ディレクティブを使用して明示的なキャッシングを行います (Next.js 16+)。
"use cache";
import { cacheLife, cacheTag } from "next/cache";
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
cacheTag(`product-${id}`);
cacheLife("hours");
const product = await fetchProduct(id);
return <ProductDetail product={product} />;
}
キャッシュプロファイル、オンデマンドリバリデーション、高度なパターンについては references/caching-strategies.md を参照してください。
Route Handler
// app/api/users/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
return NextResponse.json(await db.user.findMany());
}
export async function POST(request: NextRequest) {
const body = await request.json();
return NextResponse.json(await db.user.create({ data: body }), { status: 201 });
}
動的セグメントは [param] を使用します:
// app/api/users/[id]/route.ts
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const user = await db.user.findUnique({ where: { id } });
if (!user) return NextResponse.json({ error: "Not found" }, { status: 404 });
return NextResponse.json(user);
}
Next.js 16 Async API
すべての Next.js API はバージョン 16 で async です。
import { cookies, headers } from "next/headers";
export default async function Page() {
const cookieStore = await cookies();
const headersList = await headers();
const session = cookieStore.get("session")?.value;
const userAgent = headersList.get("user-agent");
return <div>...</div>;
}
params と searchParams も Promise ベースです:
export default async function Page({
params,
searchParams,
}: {
params: Promise<{ slug: string }>;
searchParams: Promise<{ sort?: string }>;
}) {
const { slug } = await params;
const { sort } = await searchParams;
// ...
}
移行ガイドと proxy.ts 構成については references/nextjs16-migration.md を参照してください。
パラレルルート
パラレルルートスロットに @folder 規約を使用します。
// app/dashboard/layout.tsx
export default function DashboardLayout({ children, team, analytics }: Record<string, React.ReactNode>) {
return (
<div>
{children}
<div className="grid grid-cols-2">{team}{analytics}</div>
</div>
);
}
// app/dashboard/@team/page.tsx
export default function TeamPage() { return <div>Team Section</div>; }
// app/dashboard/@analytics/page.tsx
export default function AnalyticsPage() { return <div>Analytics Section</div>; }
インターセプティングルート、ルートグループ、動的ルートについては references/routing-patterns.md を参照してください。
ベストプラクティス
Server 対 Client の判断:
- Server Component (デフォルト) から始める
- Client Component を使用するのは以下の場合のみ: React フック (useState、useEffect)、ブラウザ API (window、document)、イベントハンドラー (onClick、onSubmit)、またはクライアント専用ライブラリ
データフェッチング:
- 可能な限り Server Components でフェッチする
- React の
cache()を重複排除に使用する - 独立したフェッチを並列化する
loading.tsxで Suspense 境界を追加する
パフォーマンスチェックリスト:
- Suspense 境界に
loading.tsxを使用する - 最適化された画像に
next/imageを使用する - フォント最適化に
next/fontを使用する - エラーハンドリングに
error.tsxとnot-found.tsxを追加する
例
例 1: Server Action を使用したブログポストフォーム
入力: Zod バリデーション付きのブログ投稿フォームを作成する
出力:
// app/blog/actions.ts
"use server";
import { z } from "zod";
import { revalidatePath } from "next/cache";
const schema = z.object({ title: z.string().min(5), content: z.string().min(10) });
export async function createPost(formData: FormData) {
const parsed = schema.safeParse({ title: formData.get("title"), content: formData.get("content") });
if (!parsed.success) return { errors: parsed.error.flatten().fieldErrors };
await db.post.create({ data: parsed.data });
revalidatePath("/blog");
return { success: true };
}
// app/blog/new/page.tsx
"use client";
import { useActionState } from "react";
import { createPost } from "../actions";
export default function NewPostPage() {
const [state, formAction, pending] = useActionState(createPost, {});
return (
<form action={formAction}>
<input name="title" placeholder="Title" />
{state.errors?.title && <span>{state.errors.title[0]}</span>}
<textarea name="content" placeholder="Content" />
{state.errors?.content && <span>{state.errors.content[0]}</span>}
<button type="submit" disabled={pending}>{pending ? "Publishing..." : "Publish"}</button>
</form>
);
}
例 2: キャッシュされたプロダクトページ
入力: オンデマンドリバリデーション付きのキャッシュされたプロダクトページを作成する
出力:
// app/products/[id]/page.tsx
"use cache";
import { cacheLife, cacheTag } from "next/cache";
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
cacheTag(`product-${id}`, "products");
cacheLife("hours");
const product = await db.product.findUnique({ where: { id } });
if (!product) notFound();
return <article><h1>{product.name}</h1><p>{product.description}</p></article>;
}
// app/api/revalidate/route.ts
import { revalidateTag } from "next/cache";
import { NextResponse } from "next/server";
export async function POST(request: Request) {
const { tag } = await request.json();
revalidateTag(tag);
return NextResponse.json({ revalidated: true });
}
例 3: パラレルルートを使用したダッシュボード
入力: サイドバーと統計エリアを備えたダッシュボードを作成する
出力:
// app/dashboard/layout.tsx
export default function DashboardLayout({ children, sidebar, stats }: Record<string, React.ReactNode>) {
return (
<div className="flex">
<aside className="w-64">{sidebar}</aside>
<main className="flex-1"><div className="grid grid-cols-3">{stats}</div>{children}</main>
</div>
);
}
// app/dashboard/@sidebar/page.tsx
export default function Sidebar() { return <nav>{/* Navigation links */}</nav>; }
// app/dashboard/@stats/page.tsx
export default async function Stats() {
const stats = await fetchStats();
return <><div>Users: {stats.users}</div><div>Orders: {stats.orders}</div></>;
}
制約と警告
制約:
- Server Components はブラウザ API または React フックを使用できません
- Client Components は async にできません (直接のデータフェッチングなし)
cookies()、headers()、draftMode()は Next.js 16 で async ですparamsとsearchParamsは Next.js 16 で Promise ベースです- Server Actions は
"use server"ディレクティブで定義する必要があります
警告:
- Client Component で
awaitを使用するとビルドエラーが発生します - Server Components で
windowまたはdocumentにアクセスするとエラーがスローされます - Next.js 16 で
cookies()またはheaders()をアウェイトし忘れると、値の代わりに Promise が返されます - 適切なバリデーションのない Server Actions はデータベースを不正アクセスにさらす可能性があります
- 外部データフェッチング: 第三者 URL をフェッチする Server Components は信頼されていないコンテンツを処理します — 常にレスポンスを検証、サニタイズ、型チェックしてください; API URL をハードコードするのではなく環境変数を使用してください
リファレンス
references/app-router-fundamentals.md— Server/Client Components、ファイル規約、ナビゲーションreferences/routing-patterns.md— パラレルルート、インターセプティングルート、ルートグループreferences/caching-strategies.md— "use cache"、cacheLife、cacheTag、リバリデーションreferences/server-actions.md— Server Actions、useActionState、バリデーション、楽観的更新references/nextjs16-migration.md— Async API、proxy.ts、Turbopack、設定references/data-fetching.md— データパターン、Suspense、ストリーミングreferences/metadata-api.md— generateMetadata、OpenGraph、サイトマップ
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- giuseppe-trisciuoglio
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。