Next应用路由

Universal

nextjs-app-router

by giuseppe-trisciuoglio

聚焦Next.js16+ App Router,梳理Server Actions、route.ts、use cache和并行/拦截路由,适合项目搭建、文件约定落地与proxy.ts迁移。

216编码与调试未扫描2026年3月5日

安装

claude skill add --url github.com/giuseppe-trisciuoglio/developer-kit/tree/main/plugins/developer-kit-typescript/skills/nextjs-app-router

文档

Next.js App Router (Next.js 16+)

Build modern React applications using Next.js 16+ with App Router architecture.

Overview

This skill provides patterns for:

  • Server Components (default) and Client Components ("use client")
  • Server Actions for mutations and form handling
  • Route Handlers for API endpoints
  • Explicit caching with "use cache" directive
  • Parallel and intercepting routes
  • Next.js 16 async APIs and proxy.ts

When to Use

Activate when user requests involve:

  • "Create a Next.js 16 project", "Set up App Router"
  • "Server Component", "Client Component", "use client"
  • "Server Action", "form submission", "mutation"
  • "Route Handler", "API endpoint", "route.ts"
  • "use cache", "cacheLife", "cacheTag", "revalidation"
  • "parallel routes", "@slot", "intercepting routes"
  • "proxy.ts", "migrate from middleware.ts"
  • "layout.tsx", "page.tsx", "loading.tsx", "error.tsx", "not-found.tsx"
  • "generateMetadata", "next/image", "next/font"

Quick Reference

File Conventions

FilePurpose
page.tsxRoute page component
layout.tsxShared layout wrapper
loading.tsxSuspense loading UI
error.tsxError boundary
not-found.tsx404 page
template.tsxRe-mounting layout
route.tsAPI Route Handler
default.tsxParallel route fallback
proxy.tsRouting boundary (Next.js 16)

Directives

DirectivePurpose
"use server"Mark Server Action functions
"use client"Mark Client Component boundary
"use cache"Enable explicit caching (Next.js 16)

Instructions

Create New Project

bash
npx create-next-app@latest my-app --typescript --tailwind --app --turbopack

Implement Server Component

Server Components are the default in App Router.

tsx
// 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>
  );
}

Implement Client Component

Add "use client" when using hooks, browser APIs, or event handlers.

tsx
"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>
  );
}

Create Server Action

Define actions in separate files with "use server" directive.

tsx
// 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");
}

Use with forms in Client Components:

tsx
"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>
  );
}

See references/server-actions.md for validation with Zod, optimistic updates, and advanced patterns.

Configure Caching

Use "use cache" directive for explicit caching (Next.js 16+).

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}`);
  cacheLife("hours");

  const product = await fetchProduct(id);
  return <ProductDetail product={product} />;
}

See references/caching-strategies.md for cache profiles, on-demand revalidation, and advanced caching patterns.

Create Route Handler

Implement API endpoints using Route Handlers.

ts
// app/api/users/route.ts
import { NextRequest, NextResponse } from "next/server";

export async function GET(request: NextRequest) {
  const users = await db.user.findMany();
  return NextResponse.json(users);
}

export async function POST(request: NextRequest) {
  const body = await request.json();
  const user = await db.user.create({ data: body });
  return NextResponse.json(user, { status: 201 });
}

Dynamic segments use [param]:

ts
// app/api/users/[id]/route.ts
interface RouteParams {
  params: Promise<{ id: string }>;
}

export async function GET(request: NextRequest, { params }: RouteParams) {
  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);
}

Handle Next.js 16 Async APIs

All Next.js APIs are async in version 16.

tsx
import { cookies, headers, draftMode } from "next/headers";

export default async function Page() {
  const cookieStore = await cookies();
  const headersList = await headers();
  const { isEnabled } = await draftMode();

  const session = cookieStore.get("session")?.value;
  const userAgent = headersList.get("user-agent");

  return <div>...</div>;
}

Params and searchParams are also async:

tsx
export default async function Page({
  params,
  searchParams,
}: {
  params: Promise<{ slug: string }>;
  searchParams: Promise<{ sort?: string }>;
}) {
  const { slug } = await params;
  const { sort } = await searchParams;
  // ...
}

See references/nextjs16-migration.md for migration guide and proxy.ts configuration.

Implement Parallel Routes

Use @folder convention for parallel route slots.

tsx
// app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
  team,
  analytics,
}: {
  children: React.ReactNode;
  team: React.ReactNode;
  analytics: React.ReactNode;
}) {
  return (
    <div>
      {children}
      <div className="grid grid-cols-2">
        {team}
        {analytics}
      </div>
    </div>
  );
}
tsx
// 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>;
}

See references/routing-patterns.md for intercepting routes, route groups, and dynamic routes.

Best Practices

Server vs Client Decision

  1. Start with Server Component (default)
  2. Use Client Component only for:
    • React hooks (useState, useEffect, useContext)
    • Browser APIs (window, document, localStorage)
    • Event handlers (onClick, onSubmit)
    • Client-only libraries

Data Fetching

  • Fetch in Server Components when possible
  • Use React's cache() for deduplication
  • Parallelize independent fetches
  • Add Suspense boundaries with loading.tsx

Caching Strategy

tsx
"use cache";
import { cacheLife, cacheTag } from "next/cache";

// Set cache duration
cacheLife("hours");

// Tag for revalidation
cacheTag("resource-name");

Performance Checklist

  • Use loading.tsx for Suspense boundaries
  • Use next/image for optimized images
  • Use next/font for font optimization
  • Enable React Compiler in next.config.ts
  • Add error.tsx for error handling
  • Add not-found.tsx for 404 handling

Examples

Example 1: Create Blog Post with Server Action

Input: Create a form to submit blog posts with validation

Output:

tsx
// 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 };
}
tsx
// 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>
  );
}

Example 2: Product Page with Caching

Input: Create a cached product page with revalidation

Output:

tsx
// 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>
      <p>${product.price}</p>
    </article>
  );
}
tsx
// 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 });
}

Example 3: Dashboard with Parallel Routes

Input: Create a dashboard with sidebar and main content areas

Output:

tsx
// app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
  sidebar,
  stats,
}: {
  children: React.ReactNode;
  sidebar: React.ReactNode;
  stats: 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>
  );
}
tsx
// 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>
      <div>Revenue: {stats.revenue}</div>
    </>
  );
}

Constraints and Warnings

Constraints

  • Server Components cannot use browser APIs or React hooks
  • Client Components cannot be async (no direct data fetching)
  • cookies(), headers(), draftMode() are async in Next.js 16
  • params and searchParams are Promise-based in Next.js 16
  • Server Actions must be defined with "use server" directive

Warnings

  • Attempting to use await in a Client Component will cause a build error
  • Accessing window or document in Server Components will throw an error
  • Forgetting to await cookies() or headers() in Next.js 16 will result in a Promise instead of the actual values
  • Server Actions without proper validation can expose your database to unauthorized access
  • External Data Fetching: Server Components that fetch data from external APIs (fetch() calls to third-party URLs) process untrusted content; always validate, sanitize, and type-check fetched responses before rendering, and use environment variables for API URLs rather than hardcoding them

References

Consult these files for detailed patterns:

相关 Skills

网页构建器

by anthropics

Universal
热门

面向复杂 claude.ai HTML artifact 开发,快速初始化 React + Tailwind CSS + shadcn/ui 项目并打包为单文件 HTML,适合需要状态管理、路由或多组件交互的页面。

在 claude.ai 里做复杂网页 Artifact 很省心,多组件、状态和路由都能顺手搭起来,React、Tailwind 与 shadcn/ui 组合效率高、成品也更精致。

编码与调试
未扫描121.2k

前端设计

by anthropics

Universal
热门

面向组件、页面、海报和 Web 应用开发,按鲜明视觉方向生成可直接落地的前端代码与高质感 UI,适合做 landing page、Dashboard 或美化现有界面,避开千篇一律的 AI 审美。

想把页面做得既能上线又有设计感,就用前端设计:组件到整站都能产出,难得的是能避开千篇一律的 AI 味。

编码与调试
未扫描121.2k

网页应用测试

by anthropics

Universal
热门

用 Playwright 为本地 Web 应用编写自动化测试,支持启动开发服务器、校验前端交互、排查 UI 异常、抓取截图与浏览器日志,适合调试动态页面和回归验证。

借助 Playwright 一站式验证本地 Web 应用前端功能,调 UI 时还能同步查看日志和截图,定位问题更快。

编码与调试
未扫描121.2k

相关 MCP 服务

GitHub

编辑精选

by GitHub

热门

GitHub 是 MCP 官方参考服务器,让 Claude 直接读写你的代码仓库和 Issues。

这个参考服务器解决了开发者想让 AI 安全访问 GitHub 数据的问题,适合需要自动化代码审查或 Issue 管理的团队。但注意它只是参考实现,生产环境得自己加固安全。

编码与调试
84.2k

by Context7

热门

Context7 是实时拉取最新文档和代码示例的智能助手,让你告别过时资料。

它能解决开发者查找文档时信息滞后的问题,特别适合快速上手新库或跟进更新。不过,依赖外部源可能导致偶尔的数据延迟,建议结合官方文档使用。

编码与调试
53.3k

by tldraw

热门

tldraw 是让 AI 助手直接在无限画布上绘图和协作的 MCP 服务器。

这解决了 AI 只能输出文本、无法视觉化协作的痛点——想象让 Claude 帮你画流程图或白板讨论。最适合需要快速原型设计或头脑风暴的开发者。不过,目前它只是个基础连接器,你得自己搭建画布应用才能发挥全部潜力。

编码与调试
46.4k

评论