nextjs

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Next.js App Router - Production Patterns

Next.js App Router - 生产环境模式

Version: Next.js 16.0.0 React Version: 19.2.0 Node.js: 20.9+ Last Verified: 2025-10-24

版本: Next.js 16.0.0 React版本: 19.2.0 Node.js: 20.9+ 最后验证时间: 2025-10-24

Table of Contents

目录

When to Use This Skill

何时使用本技能

Use this skill when you need:
  • Next.js 16 App Router patterns (layouts, loading, error boundaries, routing)
  • Server Components best practices (data fetching, composition, streaming)
  • Server Actions patterns (forms, mutations, revalidation, error handling)
  • Cache Components with
    "use cache"
    directive (NEW in Next.js 16)
  • New caching APIs:
    revalidateTag()
    ,
    updateTag()
    ,
    refresh()
    (Updated in Next.js 16)
  • Migration from Next.js 15 to 16 (async params, proxy.ts, parallel routes)
  • Route Handlers (API endpoints, webhooks, streaming responses)
  • Proxy patterns (
    proxy.ts
    replaces
    middleware.ts
    in Next.js 16)
  • Async route params (
    params
    ,
    searchParams
    ,
    cookies()
    ,
    headers()
    now async)
  • Parallel routes with default.js (breaking change in Next.js 16)
  • React 19.2 features (View Transitions,
    useEffectEvent()
    , React Compiler)
  • Metadata API (SEO, Open Graph, Twitter Cards, sitemaps)
  • Image optimization (
    next/image
    with updated defaults in Next.js 16)
  • Font optimization (
    next/font
    patterns)
  • Turbopack configuration (stable and default in Next.js 16)
  • Performance optimization (lazy loading, code splitting, PPR, ISR)
  • TypeScript configuration (strict mode, path aliases)

当你需要以下功能时使用本技能:
  • Next.js 16 App Router模式(布局、加载、错误边界、路由)
  • Server Components最佳实践(数据获取、组件组合、流式渲染)
  • Server Actions模式(表单、数据变更、缓存重新验证、错误处理)
  • 使用
    "use cache"
    指令的Cache Components
    (Next.js 16新增)
  • 新缓存API:
    revalidateTag()
    updateTag()
    refresh()
    (Next.js 16更新)
  • 从Next.js 15迁移到16(异步参数、proxy.ts、并行路由)
  • Route Handlers(API端点、Webhook、流式响应)
  • Proxy模式(Next.js 16中
    proxy.ts
    替代
    middleware.ts
  • 异步路由参数
    params
    searchParams
    cookies()
    headers()
    现在为异步)
  • 带default.js的并行路由(Next.js 16中的重大变更)
  • React 19.2特性(View Transitions、
    useEffectEvent()
    、React Compiler)
  • 元数据API(SEO、Open Graph、Twitter卡片、站点地图)
  • 图片优化(Next.js 16中
    next/image
    的默认配置更新)
  • 字体优化
    next/font
    模式)
  • Turbopack配置(Next.js 16中稳定并成为默认)
  • 性能优化(懒加载、代码分割、PPR、ISR)
  • TypeScript配置(严格模式、路径别名)

When NOT to Use This Skill

何时不使用本技能

Do NOT use this skill for:
  • Cloudflare Workers deployment → Use
    cloudflare-nextjs
    skill instead
  • Pages Router patterns → This skill covers App Router ONLY (Pages Router is legacy)
  • Authentication libraries → Use
    clerk-auth
    ,
    auth-js
    , or other auth-specific skills
  • Database integration → Use
    cloudflare-d1
    ,
    drizzle-orm-d1
    , or database-specific skills
  • UI component libraries → Use
    tailwind-v4-shadcn
    skill for Tailwind + shadcn/ui
  • State management → Use
    zustand-state-management
    ,
    tanstack-query
    skills
  • Form libraries → Use
    react-hook-form-zod
    skill
  • Vercel-specific features → Refer to Vercel platform documentation
  • Next.js Enterprise features (ISR, DPR) → Refer to Next.js Enterprise docs
  • Deployment configuration → Use platform-specific deployment skills
Relationship with Other Skills:
  • cloudflare-nextjs: For deploying Next.js to Cloudflare Workers (use BOTH skills together if deploying to Cloudflare)
  • tailwind-v4-shadcn: For Tailwind v4 + shadcn/ui setup (composable with this skill)
  • clerk-auth: For Clerk authentication in Next.js (composable with this skill)
  • auth-js: For Auth.js (NextAuth) integration (composable with this skill)

请勿在以下场景使用本技能:
  • Cloudflare Workers部署 → 请改用
    cloudflare-nextjs
    技能
  • Pages Router模式 → 本技能仅覆盖App Router(Pages Router为遗留方案)
  • 认证库 → 使用
    clerk-auth
    auth-js
    或其他专注于认证的技能
  • 数据库集成 → 使用
    cloudflare-d1
    drizzle-orm-d1
    或数据库专属技能
  • UI组件库 → 使用
    tailwind-v4-shadcn
    技能处理Tailwind + shadcn/ui
  • 状态管理 → 使用
    zustand-state-management
    tanstack-query
    技能
  • 表单库 → 使用
    react-hook-form-zod
    技能
  • Vercel专属特性 → 参考Vercel平台文档
  • Next.js企业特性(ISR、DPR)→ 参考Next.js企业文档
  • 部署配置 → 使用平台专属的部署技能
与其他技能的关系:
  • cloudflare-nextjs: 用于将Next.js部署到Cloudflare Workers(如果部署到Cloudflare可同时使用两个技能)
  • tailwind-v4-shadcn: 用于Tailwind v4 + shadcn/ui设置(可与本技能组合使用)
  • clerk-auth: 用于Next.js中的Clerk认证(可与本技能组合使用)
  • auth-js: 用于Auth.js(NextAuth)集成(可与本技能组合使用)

Next.js 16 Breaking Changes

Next.js 16重大变更

IMPORTANT: Next.js 16 introduces multiple breaking changes. Read this section carefully if migrating from Next.js 15 or earlier.
重要提示: Next.js 16引入多项重大变更。如果从Next.js 15或更早版本迁移,请仔细阅读本节内容。

1. Async Route Parameters (BREAKING)

1. 异步路由参数(重大变更)

Breaking Change:
params
,
searchParams
,
cookies()
,
headers()
,
draftMode()
are now async and must be awaited.
Before (Next.js 15):
typescript
// ❌ 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>
}
After (Next.js 16):
typescript
// ✅ 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>
}
Applies to:
  • params
    in pages, layouts, route handlers
  • searchParams
    in pages
  • cookies()
    from
    next/headers
  • headers()
    from
    next/headers
  • draftMode()
    from
    next/headers
Migration:
typescript
// ❌ 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: Run
npx @next/codemod@canary upgrade latest
to automatically migrate.
See Template:
templates/app-router-async-params.tsx

变更:
params
searchParams
cookies()
headers()
draftMode()
现在为异步,必须使用await。
之前(Next.js 15):
typescript
// ❌ 此代码在Next.js 16中不再生效
export default function Page({ params, searchParams }: {
  params: { slug: string }
  searchParams: { query: string }
}) {
  const slug = params.slug // ❌ 错误:params是Promise
  const query = searchParams.query // ❌ 错误:searchParams是Promise
  return <div>{slug}</div>
}
之后(Next.js 16):
typescript
// ✅ 正确写法:await params和searchParams
export default async function Page({ params, searchParams }: {
  params: Promise<{ slug: string }>
  searchParams: Promise<{ query: string }>
}) {
  const { slug } = await params // ✅ 等待Promise
  const { query } = await searchParams // ✅ 等待Promise
  return <div>{slug}</div>
}
适用范围:
  • 页面、布局、Route Handlers中的
    params
  • 页面中的
    searchParams
  • next/headers
    中的
    cookies()
  • next/headers
    中的
    headers()
  • next/headers
    中的
    draftMode()
迁移示例:
typescript
// ❌ 之前
import { cookies, headers } from 'next/headers'

export function MyComponent() {
  const cookieStore = cookies() // ❌ 同步访问
  const headersList = headers() // ❌ 同步访问
}

// ✅ 之后
import { cookies, headers } from 'next/headers'

export async function MyComponent() {
  const cookieStore = await cookies() // ✅ 异步访问
  const headersList = await headers() // ✅ 异步访问
}
代码迁移工具: 运行
npx @next/codemod@canary upgrade latest
自动完成迁移。
查看模板:
templates/app-router-async-params.tsx

2. Middleware → Proxy Migration (BREAKING)

2. Middleware → Proxy迁移(重大变更)

Breaking Change:
middleware.ts
is deprecated in Next.js 16. Use
proxy.ts
instead.
Why the Change:
proxy.ts
makes the network boundary explicit by running on Node.js runtime (not Edge runtime). This provides better clarity between edge middleware and server-side proxies.
Migration Steps:
  1. Rename file:
    middleware.ts
    proxy.ts
  2. Rename function:
    middleware
    proxy
  3. Update config:
    matcher
    config.matcher
    (same syntax)
Before (Next.js 15):
typescript
// 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*',
}
After (Next.js 16):
typescript
// 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*',
}
Note:
middleware.ts
still works in Next.js 16 but is deprecated. Migrate to
proxy.ts
for future compatibility.
See Template:
templates/proxy-migration.ts
See Reference:
references/proxy-vs-middleware.md

变更:
middleware.ts
在Next.js 16中被弃用,请改用
proxy.ts
变更原因:
proxy.ts
通过在Node.js运行时(而非Edge运行时)运行,明确了网络边界。这让边缘中间件和服务器端代理的职责划分更清晰。
迁移步骤:
  1. 重命名文件:
    middleware.ts
    proxy.ts
  2. 重命名函数:
    middleware
    proxy
  3. 更新配置:
    matcher
    config.matcher
    (语法保持不变)
之前(Next.js 15):
typescript
// middleware.ts ❌ 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):
typescript
// proxy.ts ✅ 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*',
}
注意:
middleware.ts
在Next.js 16中仍可运行但已被弃用。为了未来兼容性,请迁移到
proxy.ts
查看模板:
templates/proxy-migration.ts
参考文档:
references/proxy-vs-middleware.md

3. Parallel Routes Require
default.js
(BREAKING)

3. 并行路由需要
default.js
(重大变更)

Breaking Change: Parallel routes now require explicit
default.js
files. Without them, routes will fail during soft navigation.
Structure:
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
Layout:
typescript
// 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>
  )
}
Default Fallback (REQUIRED):
typescript
// app/@auth/default.tsx
export default function AuthDefault() {
  return null // or <Skeleton /> or redirect
}

// app/@dashboard/default.tsx
export default function DashboardDefault() {
  return null
}
Why Required: Next.js 16 changed how parallel routes handle soft navigation. Without
default.js
, unmatched slots will error during client-side navigation.
See Template:
templates/parallel-routes-with-default.tsx

变更: 并行路由现在必须显式包含
default.js
文件。如果没有,在软导航时路由会失败。
目录结构:
app/
├── @auth/
│   ├── login/
│   │   └── page.tsx
│   └── default.tsx    ← Next.js 16中必须
├── @dashboard/
│   ├── overview/
│   │   └── page.tsx
│   └── default.tsx    ← Next.js 16中必须
└── layout.tsx
布局文件:
typescript
// 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>
  )
}
默认回退组件(必须):
typescript
// app/@auth/default.tsx
export default function AuthDefault() {
  return null // 或<Skeleton />或重定向
}

// app/@dashboard/default.tsx
export default function DashboardDefault() {
  return null
}
为什么必须: Next.js 16改变了并行路由处理软导航的方式。如果没有
default.js
,不匹配的路由槽在客户端导航时会报错。
查看模板:
templates/parallel-routes-with-default.tsx

4. Removed Features (BREAKING)

4. 移除的特性(重大变更)

The following features are REMOVED in Next.js 16:
  1. AMP Support - Entirely removed. Migrate to standard pages.
  2. next lint
    command
    - Use ESLint or Biome directly.
  3. serverRuntimeConfig
    and
    publicRuntimeConfig
    - Use environment variables instead.
  4. experimental.ppr
    flag
    - Evolved into Cache Components. Use
    "use cache"
    directive.
  5. Automatic
    scroll-behavior: smooth
    - Add manually if needed.
  6. Node.js 18 support - Minimum version is now 20.9+.
Migration:
  • AMP: Convert AMP pages to standard pages or use separate AMP implementation.
  • Linting: Run
    npx eslint .
    or
    npx biome lint .
    directly.
  • Config: Replace
    serverRuntimeConfig
    with
    process.env.VARIABLE
    .
  • PPR: Migrate from
    experimental.ppr
    to
    "use cache"
    directive (see Cache Components section).

以下特性在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实现。
  • 代码检查: 直接运行
    npx eslint .
    npx biome lint .
  • 配置: 用
    process.env.VARIABLE
    替换
    serverRuntimeConfig
  • PPR: 从
    experimental.ppr
    迁移到
    "use cache"
    指令(查看Cache Components章节)。

5. Version Requirements (BREAKING)

5. 版本要求(重大变更)

Next.js 16 requires:
  • Node.js: 20.9+ (Node.js 18 no longer supported)
  • TypeScript: 5.1+ (if using TypeScript)
  • React: 19.2+ (automatically installed with Next.js 16)
  • Browsers: Chrome 111+, Safari 16.4+, Firefox 109+, Edge 111+
Check Versions:
bash
node --version    # Should be 20.9+
npm --version     # Should be 10+
npx next --version # Should be 16.0.0+
Upgrade Node.js:
bash
undefined
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+
检查版本:
bash
node --version    # 应为20.9+
npm --version     # 应为10+
npx next --version # 应为16.0.0+
升级Node.js:
bash
undefined

Using nvm

使用nvm

nvm install 20 nvm use 20 nvm alias default 20
nvm install 20 nvm use 20 nvm alias default 20

Using Homebrew (macOS)

使用Homebrew(macOS)

brew install node@20
brew install node@20

Using apt (Ubuntu/Debian)

使用apt(Ubuntu/Debian)

sudo apt update sudo apt install nodejs npm

---
sudo apt update sudo apt install nodejs npm

---

6. Image Defaults Changed (BREAKING)

6. 图片默认配置变更(重大变更)

Next.js 16 changed
next/image
defaults
:
SettingNext.js 15Next.js 16
TTL (cache duration)60 seconds4 hours
imageSizes
[16, 32, 48, 64, 96, 128, 256, 384]
[640, 750, 828, 1080, 1200]
(reduced)
qualities
[75, 90, 100]
[75]
(single quality)
Impact:
  • Images cache longer (4 hours vs 60 seconds)
  • Fewer image sizes generated (smaller builds, but less granular)
  • Single quality (75) generated instead of multiple
Override Defaults (if needed):
typescript
// 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
See Template:
templates/image-optimization.tsx

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]
(仅单质量)
影响:
  • 图片缓存时间更长(4小时对比60秒)
  • 生成的图片尺寸更少(构建包更小,但粒度更粗)
  • 仅生成单质量(75)的图片
覆盖默认配置(如果需要):
typescript
// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    minimumCacheTTL: 60, // 恢复为60秒
    deviceSizes: [640, 750, 828, 1080, 1200, 1920], // 添加更大尺寸
    imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], // 恢复旧尺寸
    formats: ['image/webp'], // 默认值
  },
}

export default config
查看模板:
templates/image-optimization.tsx

Cache Components & Caching APIs

Cache Components与缓存API

NEW in Next.js 16: Cache Components introduce opt-in caching with the
"use cache"
directive, replacing implicit caching from Next.js 15.
Next.js 16新增: Cache Components通过
"use cache"
指令引入可选缓存,替代了Next.js 15中的隐式缓存。

1. Overview

1. 概述

What Changed:
  • Next.js 15: Implicit caching (all Server Components cached by default)
  • Next.js 16: Opt-in caching with
    "use cache"
    directive
Why the Change: Explicit caching gives developers more control and makes caching behavior predictable.
Cache Components enable:
  • Component-level caching (cache specific components, not entire pages)
  • Function-level caching (cache expensive computations)
  • Page-level caching (cache entire pages selectively)
  • Partial Prerendering (PPR) - Cache static parts, render dynamic parts on-demand

变更内容:
  • Next.js 15: 隐式缓存(所有Server Components默认缓存)
  • Next.js 16: 通过
    "use cache"
    指令实现可选缓存
变更原因: 显式缓存让开发者拥有更多控制权,使缓存行为可预测。
Cache Components支持:
  • 组件级缓存(仅缓存特定组件,而非整个页面)
  • 函数级缓存(缓存昂贵的计算)
  • 页面级缓存(选择性缓存整个页面)
  • 部分预渲染(PPR) - 缓存静态部分,按需渲染动态部分

2.
"use cache"
Directive

2.
"use cache"
指令

Syntax: Add
"use cache"
at the top of a Server Component, function, or route handler.
Component-level caching:
typescript
// 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>
  )
}
Function-level caching:
typescript
// 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>
}
Page-level caching:
typescript
// 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>
  )
}
See Template:
templates/cache-component-use-cache.tsx

语法: 在Server Component、函数或Route Handler的顶部添加
"use cache"
组件级缓存:
typescript
// 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>
  )
}
函数级缓存:
typescript
// lib/data.ts
'use cache'

export async function getExpensiveData(id: string) {
  const response = await fetch(`https://api.example.com/items/${id}`)
  return response.json()
}

// 在组件中使用
import { getExpensiveData } from '@/lib/data'

export async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const product = await getExpensiveData(id) // 已缓存

  return <div>{product.name}</div>
}
页面级缓存:
typescript
// 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)

3. 部分预渲染(PPR)

PPR allows caching static parts of a page while rendering dynamic parts on-demand.
Pattern:
typescript
// 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>
  )
}
When to Use PPR:
  • Page has both static and dynamic content
  • Want to cache layout/header/footer but render user-specific content
  • Need fast initial load (static parts) + personalization (dynamic parts)
See Reference:
references/cache-components-guide.md

PPR允许缓存页面的静态部分,同时按需渲染动态部分。
示例模式:
typescript
// app/dashboard/page.tsx

// 静态头部(已缓存)
'use cache'
async function StaticHeader() {
  return <header>My App</header>
}

// 动态用户信息(未缓存)
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>
}

// 页面组合两者
export default function Dashboard() {
  return (
    <div>
      <StaticHeader /> {/* 已缓存 */}
      <DynamicUserInfo /> {/* 动态 */}
    </div>
  )
}
何时使用PPR:
  • 页面同时包含静态和动态内容
  • 希望缓存布局/头部/页脚,但渲染用户专属内容
  • 需要快速初始加载(静态部分)+ 个性化(动态部分)
参考文档:
references/cache-components-guide.md

4.
revalidateTag()
- Updated API

4.
revalidateTag()
- 更新后的API

BREAKING CHANGE:
revalidateTag()
now requires a second argument (
cacheLife
profile) for stale-while-revalidate behavior.
Before (Next.js 15):
typescript
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
}
After (Next.js 16):
typescript
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
}
Built-in Cache Life Profiles:
  • 'max'
    - Maximum staleness (recommended for most use cases)
  • 'hours'
    - Stale after hours
  • 'days'
    - Stale after days
  • 'weeks'
    - Stale after weeks
  • 'default'
    - Default cache behavior
Custom Cache Life Profile:
typescript
revalidateTag('posts', {
  stale: 3600, // Stale after 1 hour (seconds)
  revalidate: 86400, // Revalidate every 24 hours (seconds)
  expire: false, // Never expire (optional)
})
Pattern in Server Actions:
typescript
'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
}
See Template:
templates/revalidate-tag-cache-life.ts

重大变更:
revalidateTag()
现在需要第二个参数
cacheLife
配置文件)来实现stale-while-revalidate行为。
之前(Next.js 15):
typescript
import { revalidateTag } from 'next/cache'

export async function updatePost(id: string) {
  await fetch(`/api/posts/${id}`, { method: 'PATCH' })
  revalidateTag('posts') // ❌ Next.js 15中仅需一个参数
}
之后(Next.js 16):
typescript
import { revalidateTag } from 'next/cache'

export async function updatePost(id: string) {
  await fetch(`/api/posts/${id}`, { method: 'PATCH' })
  revalidateTag('posts', 'max') // ✅ Next.js 16中必须第二个参数
}
内置缓存时长配置文件:
  • 'max'
    - 最大过期时长(推荐大多数场景使用)
  • 'hours'
    - 数小时后过期
  • 'days'
    - 数天后过期
  • 'weeks'
    - 数周后过期
  • 'default'
    - 默认缓存行为
自定义缓存时长配置文件:
typescript
revalidateTag('posts', {
  stale: 3600, // 1小时后过期(秒)
  revalidate: 86400, // 每24小时重新验证(秒)
  expire: false, // 永不过期(可选)
})
Server Actions中的模式:
typescript
'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') // ✅ 使用最大过期时长重新验证
}
查看模板:
templates/revalidate-tag-cache-life.ts

5.
updateTag()
- NEW API (Server Actions Only)

5.
updateTag()
- 新增API(仅Server Actions可用)

NEW in Next.js 16:
updateTag()
provides read-your-writes semantics for Server Actions.
What it does:
  • Expires cache immediately
  • Refreshes data within the same request
  • Shows updated data right after mutation (no stale data)
Difference from
revalidateTag()
:
  • revalidateTag()
    : Stale-while-revalidate (shows stale data, revalidates in background)
  • updateTag()
    : Immediate refresh (expires cache, fetches fresh data in same request)
Use Case: Forms, user settings, or any mutation where user expects immediate feedback.
Pattern:
typescript
'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)
}
When to Use:
  • updateTag()
    : User settings, profile updates, critical mutations (immediate feedback)
  • revalidateTag()
    : Blog posts, product listings, non-critical updates (background revalidation)
See Template:
templates/server-action-update-tag.ts

Next.js 16新增:
updateTag()
为Server Actions提供读写一致性语义。
功能:
  • 立即过期缓存
  • 在同一请求中刷新数据
  • 数据变更后立即显示更新内容(无 stale 数据)
revalidateTag()
的区别
:
  • revalidateTag()
    : Stale-while-revalidate(显示旧数据,后台重新验证)
  • updateTag()
    : 立即刷新(过期缓存,在同一请求中获取新数据)
使用场景: 表单、用户设置或任何用户期望即时反馈的数据变更操作。
示例模式:
typescript
'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

  // 更新数据库
  await db.users.update({ name, email })

  // 立即刷新缓存(读写一致性)
  updateTag('user-profile')

  // 用户立即看到更新后的数据(无 stale 数据)
}
何时使用:
  • updateTag()
    : 用户设置、个人资料更新、关键数据变更(需要即时反馈)
  • revalidateTag()
    : 博客文章、产品列表、非关键更新(后台重新验证)
查看模板:
templates/server-action-update-tag.ts

6.
refresh()
- NEW API (Server Actions Only)

6.
refresh()
- 新增API(仅Server Actions可用)

NEW in Next.js 16:
refresh()
refreshes uncached data only (complements client-side
router.refresh()
).
When to Use:
  • Refresh dynamic data without affecting cached data
  • Complement
    router.refresh()
    on server side
Pattern:
typescript
'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
}
Difference from
revalidateTag()
and
updateTag()
:
  • refresh()
    : Only refreshes uncached data
  • revalidateTag()
    : Revalidates specific tagged data (stale-while-revalidate)
  • updateTag()
    : Immediately expires and refreshes specific tagged data
See Reference:
references/cache-components-guide.md

Next.js 16新增:
refresh()
仅刷新未缓存数据(补充客户端
router.refresh()
)。
何时使用:
  • 刷新动态数据而不影响缓存数据
  • 在服务器端补充
    router.refresh()
    的功能
示例模式:
typescript
'use server'

import { refresh } from 'next/cache'

export async function refreshDashboard() {
  // 刷新未缓存数据(如实时指标)
  refresh()

  // 缓存数据(如静态头部)保持缓存状态
}
revalidateTag()
updateTag()
的区别
:
  • refresh()
    : 仅刷新未缓存数据
  • revalidateTag()
    : 重新验证特定标签的数据(stale-while-revalidate)
  • updateTag()
    : 立即过期并刷新特定标签的数据
参考文档:
references/cache-components-guide.md

Server Components

Server Components

Server Components are React components that render on the server. They enable efficient data fetching, reduce client bundle size, and improve performance.
Server Components是在服务器端渲染的React组件。它们实现高效的数据获取、减少客户端包体积并提升性能。

1. Server Component Basics

1. Server Components基础

Default Behavior: All components in the App Router are Server Components by default (unless marked with
'use client'
).
Example:
typescript
// app/posts/page.tsx (Server Component by default)
export default async function PostsPage() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json())

  return (
    <div>
      {posts.map((post: { id: string; title: string }) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  )
}
Rules:
  • ✅ Can
    await
    promises directly in component body
  • ✅ Can access
    cookies()
    ,
    headers()
    ,
    draftMode()
    (with
    await
    )
  • ✅ Can use Node.js APIs (fs, path, etc.)
  • ❌ Cannot use browser APIs (window, document, localStorage)
  • ❌ Cannot use React hooks (
    useState
    ,
    useEffect
    , etc.)
  • ❌ Cannot use event handlers (
    onClick
    ,
    onChange
    , etc.)

默认行为: App Router中的所有组件默认都是Server Components(除非标记为
'use client'
)。
示例:
typescript
// app/posts/page.tsx(默认是Server Component)
export default async function PostsPage() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json())

  return (
    <div>
      {posts.map((post: { id: string; title: string }) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
        </article>
      ))}
    </div>
  )
}
规则:
  • ✅ 可以在组件体中直接
    await
    Promise
  • ✅ 可以访问
    cookies()
    headers()
    draftMode()
    (需
    await
  • ✅ 可以使用Node.js API(fs、path等)
  • ❌ 不能使用浏览器API(window、document、localStorage)
  • ❌ 不能使用React钩子(
    useState
    useEffect
    等)
  • ❌ 不能使用事件处理器(
    onClick
    onChange
    等)

2. Data Fetching in Server Components

2. Server Components中的数据获取

Pattern: Use
async/await
directly in component body.
typescript
// app/products/[id]/page.tsx
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params

  // Fetch data directly in component
  const product = await fetch(`https://api.example.com/products/${id}`)
    .then(r => r.json())

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>${product.price}</p>
    </div>
  )
}
Parallel Data Fetching:
typescript
export default async function Dashboard() {
  // Fetch in parallel with Promise.all
  const [user, posts, comments] = await Promise.all([
    fetch('/api/user').then(r => r.json()),
    fetch('/api/posts').then(r => r.json()),
    fetch('/api/comments').then(r => r.json()),
  ])

  return (
    <div>
      <UserInfo user={user} />
      <PostsList posts={posts} />
      <CommentsList comments={comments} />
    </div>
  )
}
Sequential Data Fetching (when needed):
typescript
export default async function UserPosts({ params }: { params: Promise<{ userId: string }> }) {
  const { userId } = await params

  // Fetch user first
  const user = await fetch(`/api/users/${userId}`).then(r => r.json())

  // Then fetch user's posts (depends on user data)
  const posts = await fetch(`/api/posts?userId=${user.id}`).then(r => r.json())

  return (
    <div>
      <h1>{user.name}'s Posts</h1>
      <ul>
        {posts.map((post: { id: string; title: string }) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}
See Template:
templates/server-component-streaming.tsx

模式: 在组件体中直接使用
async/await
typescript
// app/products/[id]/page.tsx
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params

  // 在组件中直接获取数据
  const product = await fetch(`https://api.example.com/products/${id}`)
    .then(r => r.json())

  return (
    <div>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>${product.price}</p>
    </div>
  )
}
并行数据获取:
typescript
export default async function Dashboard() {
  // 使用Promise.all并行获取
  const [user, posts, comments] = await Promise.all([
    fetch('/api/user').then(r => r.json()),
    fetch('/api/posts').then(r => r.json()),
    fetch('/api/comments').then(r => r.json()),
  ])

  return (
    <div>
      <UserInfo user={user} />
      <PostsList posts={posts} />
      <CommentsList comments={comments} />
    </div>
  )
}
顺序数据获取(当需要时):
typescript
export default async function UserPosts({ params }: { params: Promise<{ userId: string }> }) {
  const { userId } = await params

  // 先获取用户信息
  const user = await fetch(`/api/users/${userId}`).then(r => r.json())

  // 然后获取用户的文章(依赖用户数据)
  const posts = await fetch(`/api/posts?userId=${user.id}`).then(r => r.json())

  return (
    <div>
      <h1>{user.name}'s Posts</h1>
      <ul>
        {posts.map((post: { id: string; title: string }) => (
          <li key={post.id}>{post.title}</li>
        ))}
      </ul>
    </div>
  )
}
查看模板:
templates/server-component-streaming.tsx

3. Streaming with Suspense

3. 使用Suspense实现流式渲染

Pattern: Wrap slow components in
<Suspense>
to stream content as it loads.
typescript
import { Suspense } from 'react'

// Fast component (loads immediately)
async function Header() {
  return <header>My App</header>
}

// Slow component (takes 2 seconds)
async function SlowData() {
  await new Promise(resolve => setTimeout(resolve, 2000))
  const data = await fetch('/api/slow-data').then(r => r.json())
  return <div>{data.content}</div>
}

// Page streams content
export default function Page() {
  return (
    <div>
      <Header /> {/* Loads immediately */}

      <Suspense fallback={<div>Loading...</div>}>
        <SlowData /> {/* Streams when ready */}
      </Suspense>
    </div>
  )
}
When to Use Streaming:
  • Page has slow API calls
  • Want to show UI immediately (don't wait for all data)
  • Improve perceived performance
See Reference:
references/server-components-patterns.md

模式: 将加载缓慢的组件包裹在
<Suspense>
中,实现内容流式加载。
typescript
import { Suspense } from 'react'

// 快速组件(立即加载)
async function Header() {
  return <header>My App</header>
}

// 缓慢组件(需要2秒加载)
async function SlowData() {
  await new Promise(resolve => setTimeout(resolve, 2000))
  const data = await fetch('/api/slow-data').then(r => r.json())
  return <div>{data.content}</div>
}

// 页面流式渲染内容
export default function Page() {
  return (
    <div>
      <Header /> {/* 立即加载 */}

      <Suspense fallback={<div>Loading...</div>}>
        <SlowData /> {/* 准备好后流式渲染 */}
      </Suspense>
    </div>
  )
}
何时使用流式渲染:
  • 页面包含缓慢的API调用
  • 希望立即显示UI(不等待所有数据加载完成)
  • 提升感知性能
参考文档:
references/server-components-patterns.md

4. Server vs Client Components

4. Server Components vs Client Components

When to Use Server Components (default):
  • Fetch data from APIs/databases
  • Access backend resources (files, environment variables)
  • Keep large dependencies on server (reduce bundle size)
  • Render static content
When to Use Client Components (
'use client'
):
  • Need React hooks (
    useState
    ,
    useEffect
    ,
    useContext
    )
  • Need event handlers (
    onClick
    ,
    onChange
    ,
    onSubmit
    )
  • Need browser APIs (
    window
    ,
    localStorage
    ,
    navigator
    )
  • Need third-party libraries that use browser APIs (charts, maps, etc.)
Pattern: Use Server Components by default, add
'use client'
only when needed.
typescript
// app/components/interactive-button.tsx
'use client' // Client Component

import { useState } from 'react'

export function InteractiveButton() {
  const [count, setCount] = useState(0)

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  )
}

// app/page.tsx (Server Component)
import { InteractiveButton } from './components/interactive-button'

export default async function Page() {
  const data = await fetch('/api/data').then(r => r.json())

  return (
    <div>
      <h1>{data.title}</h1>
      <InteractiveButton /> {/* Client Component inside Server Component */}
    </div>
  )
}
Composition Rules:
  • ✅ Server Component can import Client Component
  • ✅ Client Component can import Client Component
  • ✅ Client Component can render Server Component as children (via props)
  • ❌ Client Component cannot import Server Component directly
See Reference:
references/server-components-patterns.md

何时使用Server Components(默认):
  • 从API/数据库获取数据
  • 访问后端资源(文件、环境变量)
  • 将大型依赖保留在服务器端(减少包体积)
  • 渲染静态内容
何时使用Client Components
'use client'
):
  • 需要React钩子(
    useState
    useEffect
    useContext
  • 需要事件处理器(
    onClick
    onChange
    onSubmit
  • 需要浏览器API(
    window
    localStorage
    navigator
  • 需要使用依赖浏览器API的第三方库(图表、地图等)
模式: 默认使用Server Components,仅在需要时添加
'use client'
typescript
// app/components/interactive-button.tsx
'use client' // Client Component

import { useState } from 'react'

export function InteractiveButton() {
  const [count, setCount] = useState(0)

  return (
    <button onClick={() => setCount(count + 1)}>
      Clicked {count} times
    </button>
  )
}

// app/page.tsx(Server Component)
import { InteractiveButton } from './components/interactive-button'

export default async function Page() {
  const data = await fetch('/api/data').then(r => r.json())

  return (
    <div>
      <h1>{data.title}</h1>
      <InteractiveButton /> {/* Server Component中嵌套Client Component */}
    </div>
  )
}
组合规则:
  • ✅ Server Component可以导入Client Component
  • ✅ Client Component可以导入Client Component
  • ✅ Client Component可以将Server Component作为子组件传递(通过props)
  • ❌ Client Component不能直接导入Server Component
参考文档:
references/server-components-patterns.md

Server Actions

Server Actions

Server Actions are asynchronous functions that run on the server. They enable server-side mutations, form handling, and data revalidation.
Server Actions是在服务器端运行的异步函数。它们实现服务器端数据变更、表单处理和缓存重新验证。

1. Server Action Basics

1. Server Actions基础

Definition: Add
'use server'
directive to create a Server Action.
File-level Server Actions:
typescript
// app/actions.ts
'use server'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string

  // Mutate database
  await db.posts.create({ title, content })

  // Revalidate cache
  revalidateTag('posts', 'max')
}
Inline Server Actions:
typescript
// app/posts/new/page.tsx
export default function NewPostPage() {
  async function createPost(formData: FormData) {
    'use server'

    const title = formData.get('title') as string
    const content = formData.get('content') as string

    await db.posts.create({ title, content })
    revalidateTag('posts', 'max')
  }

  return (
    <form action={createPost}>
      <input name="title" />
      <textarea name="content" />
      <button type="submit">Create Post</button>
    </form>
  )
}
See Template:
templates/server-actions-form.tsx

定义: 添加
'use server'
指令创建Server Action。
文件级Server Actions:
typescript
// app/actions.ts
'use server'

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string
  const content = formData.get('content') as string

  // 修改数据库
  await db.posts.create({ title, content })

  // 重新验证缓存
  revalidateTag('posts', 'max')
}
内联Server Actions:
typescript
// app/posts/new/page.tsx
export default function NewPostPage() {
  async function createPost(formData: FormData) {
    'use server'

    const title = formData.get('title') as string
    const content = formData.get('content') as string

    await db.posts.create({ title, content })
    revalidateTag('posts', 'max')
  }

  return (
    <form action={createPost}>
      <input name="title" />
      <textarea name="content" />
      <button type="submit">Create Post</button>
    </form>
  )
}
查看模板:
templates/server-actions-form.tsx

2. Form Handling

2. 表单处理

Basic Form:
typescript
// app/components/create-post-form.tsx
import { createPost } from '@/app/actions'

export function CreatePostForm() {
  return (
    <form action={createPost}>
      <label>
        Title:
        <input type="text" name="title" required />
      </label>

      <label>
        Content:
        <textarea name="content" required />
      </label>

      <button type="submit">Create Post</button>
    </form>
  )
}
With Loading State (useFormStatus):
typescript
'use client'

import { useFormStatus } from 'react-dom'
import { createPost } from '@/app/actions'

function SubmitButton() {
  const { pending } = useFormStatus()

  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Creating...' : 'Create Post'}
    </button>
  )
}

export function CreatePostForm() {
  return (
    <form action={createPost}>
      <input type="text" name="title" required />
      <textarea name="content" required />
      <SubmitButton />
    </form>
  )
}
With Validation:
typescript
// app/actions.ts
'use server'

import { z } from 'zod'
import { redirect } from 'next/navigation'

const PostSchema = z.object({
  title: z.string().min(3, 'Title must be at least 3 characters'),
  content: z.string().min(10, 'Content must be at least 10 characters'),
})

export async function createPost(formData: FormData) {
  const rawData = {
    title: formData.get('title'),
    content: formData.get('content'),
  }

  // Validate
  const parsed = PostSchema.safeParse(rawData)

  if (!parsed.success) {
    return {
      errors: parsed.error.flatten().fieldErrors,
    }
  }

  // Mutate
  await db.posts.create(parsed.data)

  // Revalidate and redirect
  revalidateTag('posts', 'max')
  redirect('/posts')
}
See Template:
templates/server-actions-form.tsx
See Reference:
references/server-actions-guide.md

基础表单:
typescript
// app/components/create-post-form.tsx
import { createPost } from '@/app/actions'

export function CreatePostForm() {
  return (
    <form action={createPost}>
      <label>
        标题:
        <input type="text" name="title" required />
      </label>

      <label>
        内容:
        <textarea name="content" required />
      </label>

      <button type="submit">创建文章</button>
    </form>
  )
}
带加载状态(useFormStatus):
typescript
'use client'

import { useFormStatus } from 'react-dom'
import { createPost } from '@/app/actions'

function SubmitButton() {
  const { pending } = useFormStatus()

  return (
    <button type="submit" disabled={pending}>
      {pending ? '创建中...' : '创建文章'}
    </button>
  )
}

export function CreatePostForm() {
  return (
    <form action={createPost}>
      <input type="text" name="title" required />
      <textarea name="content" required />
      <SubmitButton />
    </form>
  )
}
带验证:
typescript
// app/actions.ts
'use server'

import { z } from 'zod'
import { redirect } from 'next/navigation'

const PostSchema = z.object({
  title: z.string().min(3, '标题至少3个字符'),
  content: z.string().min(10, '内容至少10个字符'),
})

export async function createPost(formData: FormData) {
  const rawData = {
    title: formData.get('title'),
    content: formData.get('content'),
  }

  // 验证
  const parsed = PostSchema.safeParse(rawData)

  if (!parsed.success) {
    return {
      errors: parsed.error.flatten().fieldErrors,
    }
  }

  // 修改数据
  await db.posts.create(parsed.data)

  // 重新验证缓存并重定向
  revalidateTag('posts', 'max')
  redirect('/posts')
}
查看模板:
templates/server-actions-form.tsx
参考文档:
references/server-actions-guide.md

3. Error Handling

3. 错误处理

Pattern: Return error objects from Server Actions, handle in Client Components.
Server Action:
typescript
// app/actions.ts
'use server'

export async function deletePost(id: string) {
  try {
    await db.posts.delete({ where: { id } })
    revalidateTag('posts', 'max')
    return { success: true }
  } catch (error) {
    return {
      success: false,
      error: 'Failed to delete post. Please try again.'
    }
  }
}
Client Component:
typescript
'use client'

import { useState } from 'react'
import { deletePost } from '@/app/actions'

export function DeleteButton({ postId }: { postId: string }) {
  const [error, setError] = useState<string | null>(null)

  async function handleDelete() {
    const result = await deletePost(postId)

    if (!result.success) {
      setError(result.error)
    }
  }

  return (
    <div>
      <button onClick={handleDelete}>Delete Post</button>
      {error && <p className="error">{error}</p>}
    </div>
  )
}

模式: 从Server Actions返回错误对象,在Client Component中处理。
Server Action:
typescript
// app/actions.ts
'use server'

export async function deletePost(id: string) {
  try {
    await db.posts.delete({ where: { id } })
    revalidateTag('posts', 'max')
    return { success: true }
  } catch (error) {
    return {
      success: false,
      error: '删除文章失败,请重试。'
    }
  }
}
Client Component:
typescript
'use client'

import { useState } from 'react'
import { deletePost } from '@/app/actions'

export function DeleteButton({ postId }: { postId: string }) {
  const [error, setError] = useState<string | null>(null)

  async function handleDelete() {
    const result = await deletePost(postId)

    if (!result.success) {
      setError(result.error)
    }
  }

  return (
    <div>
      <button onClick={handleDelete}>删除文章</button>
      {error && <p className="error">{error}</p>}
    </div>
  )
}

4. Optimistic Updates

4. 乐观更新

Pattern: Show UI update immediately, then sync with server.
typescript
'use client'

import { useOptimistic } from 'react'
import { likePost } from '@/app/actions'

export function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: number }) {
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    initialLikes,
    (state, amount: number) => state + amount
  )

  async function handleLike() {
    // Update UI immediately
    addOptimisticLike(1)

    // Sync with server
    await likePost(postId)
  }

  return (
    <button onClick={handleLike}>
      ❤️ {optimisticLikes} likes
    </button>
  )
}
See Reference:
references/server-actions-guide.md

模式: 立即更新UI,然后与服务器同步。
typescript
'use client'

import { useOptimistic } from 'react'
import { likePost } from '@/app/actions'

export function LikeButton({ postId, initialLikes }: { postId: string; initialLikes: number }) {
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    initialLikes,
    (state, amount: number) => state + amount
  )

  async function handleLike() {
    // 立即更新UI
    addOptimisticLike(1)

    // 与服务器同步
    await likePost(postId)
  }

  return (
    <button onClick={handleLike}>
      ❤️ {optimisticLikes} likes
    </button>
  )
}
参考文档:
references/server-actions-guide.md

Route Handlers

Route Handlers

Route Handlers are server-side API endpoints in the App Router. They replace API Routes from the Pages Router.
Route Handlers是App Router中的服务器端API端点。它们替代了Pages Router中的API Routes。

1. Basic Route Handler

1. 基础Route Handler

File:
app/api/hello/route.ts
typescript
import { NextResponse } from 'next/server'

export async function GET() {
  return NextResponse.json({ message: 'Hello, World!' })
}

export async function POST(request: Request) {
  const body = await request.json()

  return NextResponse.json({
    message: 'Post created',
    data: body
  })
}
Supported Methods:
GET
,
POST
,
PUT
,
PATCH
,
DELETE
,
HEAD
,
OPTIONS
See Template:
templates/route-handler-api.ts

文件:
app/api/hello/route.ts
typescript
import { NextResponse } from 'next/server'

export async function GET() {
  return NextResponse.json({ message: 'Hello, World!' })
}

export async function POST(request: Request) {
  const body = await request.json()

  return NextResponse.json({
    message: 'Post created',
    data: body
  })
}
支持的方法:
GET
POST
PUT
PATCH
DELETE
HEAD
OPTIONS
查看模板:
templates/route-handler-api.ts

2. Dynamic Routes

2. 动态路由

File:
app/api/posts/[id]/route.ts
typescript
import { NextResponse } from 'next/server'

export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params // ✅ Await params in Next.js 16

  const post = await db.posts.findUnique({ where: { id } })

  if (!post) {
    return NextResponse.json(
      { error: 'Post not found' },
      { status: 404 }
    )
  }

  return NextResponse.json(post)
}

export async function DELETE(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params

  await db.posts.delete({ where: { id } })

  return NextResponse.json({ message: 'Post deleted' })
}

文件:
app/api/posts/[id]/route.ts
typescript
import { NextResponse } from 'next/server'

export async function GET(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params // ✅ Next.js 16中需await params

  const post = await db.posts.findUnique({ where: { id } })

  if (!post) {
    return NextResponse.json(
      { error: '文章未找到' },
      { status: 404 }
    )
  }

  return NextResponse.json(post)
}

export async function DELETE(
  request: Request,
  { params }: { params: Promise<{ id: string }> }
) {
  const { id } = await params

  await db.posts.delete({ where: { id } })

  return NextResponse.json({ message: '文章已删除' })
}

3. Search Params

3. 查询参数

URL:
/api/posts?tag=javascript&limit=10
typescript
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const tag = searchParams.get('tag')
  const limit = parseInt(searchParams.get('limit') || '10')

  const posts = await db.posts.findMany({
    where: { tags: { has: tag } },
    take: limit,
  })

  return NextResponse.json(posts)
}

URL:
/api/posts?tag=javascript&limit=10
typescript
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const tag = searchParams.get('tag')
  const limit = parseInt(searchParams.get('limit') || '10')

  const posts = await db.posts.findMany({
    where: { tags: { has: tag } },
    take: limit,
  })

  return NextResponse.json(posts)
}

4. Webhooks

4. Webhook

Pattern: Handle incoming webhooks from third-party services.
typescript
// app/api/webhooks/stripe/route.ts
import { NextResponse } from 'next/server'
import { headers } from 'next/headers'

export async function POST(request: Request) {
  const body = await request.text()
  const headersList = await headers() // ✅ Await headers in Next.js 16
  const signature = headersList.get('stripe-signature')

  // Verify webhook signature
  const event = stripe.webhooks.constructEvent(
    body,
    signature!,
    process.env.STRIPE_WEBHOOK_SECRET!
  )

  // Handle event
  switch (event.type) {
    case 'payment_intent.succeeded':
      await handlePaymentSuccess(event.data.object)
      break
    case 'payment_intent.failed':
      await handlePaymentFailure(event.data.object)
      break
  }

  return NextResponse.json({ received: true })
}
See Template:
templates/route-handler-api.ts
See Reference:
references/route-handlers-reference.md

模式: 处理来自第三方服务的Webhook。
typescript
// app/api/webhooks/stripe/route.ts
import { NextResponse } from 'next/server'
import { headers } from 'next/headers'

export async function POST(request: Request) {
  const body = await request.text()
  const headersList = await headers() // ✅ Next.js 16中需await headers
  const signature = headersList.get('stripe-signature')

  // 验证Webhook签名
  const event = stripe.webhooks.constructEvent(
    body,
    signature!,
    process.env.STRIPE_WEBHOOK_SECRET!
  )

  // 处理事件
  switch (event.type) {
    case 'payment_intent.succeeded':
      await handlePaymentSuccess(event.data.object)
      break
    case 'payment_intent.failed':
      await handlePaymentFailure(event.data.object)
      break
  }

  return NextResponse.json({ received: true })
}
查看模板:
templates/route-handler-api.ts
参考文档:
references/route-handlers-reference.md

Proxy vs Middleware

Proxy vs Middleware

Next.js 16 introduces
proxy.ts
to replace
middleware.ts
.
**Next.js 16引入
proxy.ts
**替代
middleware.ts

Why the Change?

变更原因

  • middleware.ts
    : Runs on Edge runtime (limited Node.js APIs)
  • proxy.ts
    : Runs on Node.js runtime (full Node.js APIs)
The new
proxy.ts
makes the network boundary explicit and provides more flexibility.
  • middleware.ts
    : 在Edge运行时运行(Node.js API有限)
  • proxy.ts
    : 在Node.js运行时运行(完整Node.js API)
新的
proxy.ts
明确了网络边界,提供了更大的灵活性。

Migration

迁移示例

Before (middleware.ts):
typescript
// 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*',
}
After (proxy.ts):
typescript
// 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*',
}
See Template:
templates/proxy-migration.ts
See Reference:
references/proxy-vs-middleware.md

之前(middleware.ts):
typescript
// middleware.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // 检查认证
  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):
typescript
// proxy.ts
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function proxy(request: NextRequest) {
  // 检查认证
  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 & Route Groups

并行路由与路由组

1. Parallel Routes

1. 并行路由

Use Case: Render multiple pages in the same layout (e.g., modal + main content, dashboard panels).
Structure:
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
Layout:
typescript
// app/layout.tsx
export default function Layout({
  children,
  modal,
  feed,
}: {
  children: React.ReactNode
  modal: React.ReactNode
  feed: React.ReactNode
}) {
  return (
    <html>
      <body>
        {modal}
        <main>
          {children}
          <aside>{feed}</aside>
        </main>
      </body>
    </html>
  )
}
Default Files (REQUIRED):
typescript
// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

// app/@feed/default.tsx
export default function FeedDefault() {
  return <div>Default Feed</div>
}
See Template:
templates/parallel-routes-with-default.tsx

使用场景: 在同一布局中渲染多个页面(如模态框+主内容、仪表板面板)。
目录结构:
app/
├── @modal/
│   ├── login/
│   │   └── page.tsx
│   └── default.tsx  ← Next.js 16中必须
├── @feed/
│   ├── trending/
│   │   └── page.tsx
│   └── default.tsx  ← Next.js 16中必须
└── layout.tsx
布局文件:
typescript
// app/layout.tsx
export default function Layout({
  children,
  modal,
  feed,
}: {
  children: React.ReactNode
  modal: React.ReactNode
  feed: React.ReactNode
}) {
  return (
    <html>
      <body>
        {modal}
        <main>
          {children}
          <aside>{feed}</aside>
        </main>
      </body>
    </html>
  )
}
默认文件(必须):
typescript
// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

// app/@feed/default.tsx
export default function FeedDefault() {
  return <div>默认信息流</div>
}
查看模板:
templates/parallel-routes-with-default.tsx

2. Route Groups

2. 路由组

Use Case: Organize routes without affecting URL structure.
Structure:
app/
├── (marketing)/
│   ├── about/
│   │   └── page.tsx       → /about
│   └── contact/
│       └── page.tsx       → /contact
├── (shop)/
│   ├── products/
│   │   └── page.tsx       → /products
│   └── cart/
│       └── page.tsx       → /cart
└── layout.tsx
Different Layouts per Group:
app/
├── (marketing)/
│   ├── layout.tsx          ← Marketing layout
│   └── about/page.tsx
├── (shop)/
│   ├── layout.tsx          ← Shop layout
│   └── products/page.tsx
└── layout.tsx              ← Root layout
See Reference:
references/app-router-fundamentals.md

使用场景: 组织路由而不影响URL结构。
目录结构:
app/
├── (marketing)/
│   ├── about/
│   │   └── page.tsx       → /about
│   └── contact/
│       └── page.tsx       → /contact
├── (shop)/
│   ├── products/
│   │   └── page.tsx       → /products
│   └── cart/
│       └── page.tsx       → /cart
└── layout.tsx
为不同组配置不同布局:
app/
├── (marketing)/
│   ├── layout.tsx          ← 营销站点布局
│   └── about/page.tsx
├── (shop)/
│   ├── layout.tsx          ← 电商站点布局
│   └── products/page.tsx
└── layout.tsx              ← 根布局
参考文档:
references/app-router-fundamentals.md

React 19.2 Features

React 19.2特性

Next.js 16 integrates React 19.2, which includes new features from React Canary.
Next.js 16集成了React 19.2,包含来自React Canary的新特性。

1. View Transitions

1. View Transitions

Use Case: Smooth animations between page transitions.
typescript
'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>
}
With CSS View Transitions API:
css
/* app/globals.css */
@view-transition {
  navigation: auto;
}

/* Animate elements with view-transition-name */
.page-title {
  view-transition-name: page-title;
}
See Template:
templates/view-transitions-react-19.tsx

使用场景: 页面切换时的平滑动画。
typescript
'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()

    // 将导航包裹在startTransition中以使用View Transitions
    startTransition(() => {
      router.push(href)
    })
  }

  return <a href={href} onClick={handleClick}>{children}</a>
}
配合CSS View Transitions API:
css
/* app/globals.css */
@view-transition {
  navigation: auto;
}

/* 为元素设置view-transition-name以实现动画 */
.page-title {
  view-transition-name: page-title;
}
查看模板:
templates/view-transitions-react-19.tsx

2.
useEffectEvent()
(Experimental)

2.
useEffectEvent()
(实验性)

Use Case: Extract non-reactive logic from
useEffect
.
typescript
'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>
}
Why Use It: Prevents unnecessary
useEffect
re-runs when callback dependencies change.

使用场景: 从
useEffect
中提取非响应式逻辑。
typescript
'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() // 非响应式回调

    return () => connection.disconnect()
  }, [roomId]) // 仅当roomId变化时重新运行

  return <div>Chat Room {roomId}</div>
}
为什么使用: 当回调依赖项变化时,避免不必要的
useEffect
重新运行。

3. React Compiler (Stable)

3. React Compiler(稳定版)

Use Case: Automatic memoization without
useMemo
,
useCallback
.
Enable in next.config.ts:
typescript
import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    reactCompiler: true,
  },
}

export default config
Install Plugin:
bash
npm install babel-plugin-react-compiler
Example (no manual memoization needed):
typescript
'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>
  )
}
See Reference:
references/react-19-integration.md

使用场景: 无需
useMemo
useCallback
即可自动实现记忆化。
在next.config.ts中启用:
typescript
import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    reactCompiler: true,
  },
}

export default config
安装插件:
bash
npm install babel-plugin-react-compiler
示例(无需手动记忆化):
typescript
'use client'

export function ExpensiveList({ items }: { items: string[] }) {
  // React Compiler自动实现记忆化
  const filteredItems = items.filter(item => item.length > 3)

  return (
    <ul>
      {filteredItems.map(item => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  )
}
参考文档:
references/react-19-integration.md

Metadata API

元数据API

The Metadata API provides type-safe SEO and social sharing metadata.
元数据API提供类型安全的SEO和社交分享元数据。

1. Static Metadata

1. 静态元数据

Pattern: Export
metadata
object from page or layout.
typescript
// app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My App',
  description: 'Welcome to my app',
  openGraph: {
    title: 'My App',
    description: 'Welcome to my app',
    images: ['/og-image.jpg'],
  },
  twitter: {
    card: 'summary_large_image',
    title: 'My App',
    description: 'Welcome to my app',
    images: ['/twitter-image.jpg'],
  },
}

export default function Page() {
  return <h1>Home</h1>
}

模式: 从页面或布局中导出
metadata
对象。
typescript
// app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: '我的应用',
  description: '欢迎来到我的应用',
  openGraph: {
    title: '我的应用',
    description: '欢迎来到我的应用',
    images: ['/og-image.jpg'],
  },
  twitter: {
    card: 'summary_large_image',
    title: '我的应用',
    description: '欢迎来到我的应用',
    images: ['/twitter-image.jpg'],
  },
}

export default function Page() {
  return <h1>首页</h1>
}

2. Dynamic Metadata

2. 动态元数据

Pattern: Export
generateMetadata
async function.
typescript
// app/posts/[id]/page.tsx
import type { Metadata } from 'next'

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,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [post.coverImage],
    },
  }
}

export default async function PostPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const post = await fetch(`/api/posts/${id}`).then(r => r.json())

  return <article>{post.content}</article>
}

模式: 导出
generateMetadata
异步函数。
typescript
// app/posts/[id]/page.tsx
import type { Metadata } from 'next'

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,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      images: [post.coverImage],
    },
  }
}

export default async function PostPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const post = await fetch(`/api/posts/${id}`).then(r => r.json())

  return <article>{post.content}</article>
}

3. Sitemap

3. 站点地图

File:
app/sitemap.ts
typescript
import type { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await fetch('/api/posts').then(r => r.json())

  const postUrls = posts.map((post: { id: string; updatedAt: string }) => ({
    url: `https://example.com/posts/${post.id}`,
    lastModified: post.updatedAt,
    changeFrequency: 'weekly' as const,
    priority: 0.8,
  }))

  return [
    {
      url: 'https://example.com',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
    ...postUrls,
  ]
}
See Template:
templates/metadata-config.ts
See Reference:
references/metadata-api-guide.md

文件:
app/sitemap.ts
typescript
import type { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await fetch('/api/posts').then(r => r.json())

  const postUrls = posts.map((post: { id: string; updatedAt: string }) => ({
    url: `https://example.com/posts/${post.id}`,
    lastModified: post.updatedAt,
    changeFrequency: 'weekly' as const,
    priority: 0.8,
  }))

  return [
    {
      url: 'https://example.com',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
    ...postUrls,
  ]
}
查看模板:
templates/metadata-config.ts
参考文档:
references/metadata-api-guide.md

Image & Font Optimization

图片与字体优化

1. next/image

1. next/image

Basic Usage:
typescript
import Image from 'next/image'

export function MyImage() {
  return (
    <Image
      src="/hero.jpg"
      alt="Hero image"
      width={1200}
      height={600}
      priority // Load above the fold
    />
  )
}
Responsive Images:
typescript
<Image
  src="/hero.jpg"
  alt="Hero"
  fill
  style={{ objectFit: 'cover' }}
  sizes="(max-width: 768px) 100vw, 50vw"
/>
Remote Images (configure in next.config.ts):
typescript
import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
}

export default config
See Template:
templates/image-optimization.tsx

基础用法:
typescript
import Image from 'next/image'

export function MyImage() {
  return (
    <Image
      src="/hero.jpg"
      alt="英雄图"
      width={1200}
      height={600}
      priority // 首屏加载
    />
  )
}
响应式图片:
typescript
<Image
  src="/hero.jpg"
  alt="英雄图"
  fill
  style={{ objectFit: 'cover' }}
  sizes="(max-width: 768px) 100vw, 50vw"
/>
远程图片(在next.config.ts中配置):
typescript
import type { NextConfig } from 'next'

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'cdn.example.com',
        pathname: '/images/**',
      },
    ],
  },
}

export default config
查看模板:
templates/image-optimization.tsx

2. next/font

2. next/font

Google Fonts:
typescript
// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

const robotoMono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inter.variable} ${robotoMono.variable}`}>
      <body>{children}</body>
    </html>
  )
}
Local Fonts:
typescript
import localFont from 'next/font/local'

const myFont = localFont({
  src: './fonts/my-font.woff2',
  display: 'swap',
  variable: '--font-my-font',
})
See Template:
templates/font-optimization.tsx

Google字体:
typescript
// app/layout.tsx
import { Inter, Roboto_Mono } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
})

const robotoMono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-roboto-mono',
})

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inter.variable} ${robotoMono.variable}`}>
      <body>{children}</body>
    </html>
  )
}
本地字体:
typescript
import localFont from 'next/font/local'

const myFont = localFont({
  src: './fonts/my-font.woff2',
  display: 'swap',
  variable: '--font-my-font',
})
查看模板:
templates/font-optimization.tsx

Performance Patterns

性能优化模式

1. Lazy Loading

1. 懒加载

Component Lazy Loading:
typescript
import dynamic from 'next/dynamic'

const HeavyComponent = dynamic(() => import('./heavy-component'), {
  loading: () => <div>Loading...</div>,
  ssr: false, // Disable SSR for client-only components
})

export default function Page() {
  return (
    <div>
      <h1>My Page</h1>
      <HeavyComponent />
    </div>
  )
}
Conditional Loading:
typescript
'use client'

import { useState } from 'react'
import dynamic from 'next/dynamic'

const Chart = dynamic(() => import('./chart'), { ssr: false })

export function Dashboard() {
  const [showChart, setShowChart] = useState(false)

  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && <Chart />}
    </div>
  )
}

组件懒加载:
typescript
import dynamic from 'next/dynamic'

const HeavyComponent = dynamic(() => import('./heavy-component'), {
  loading: () => <div>加载中...</div>,
  ssr: false, // 仅客户端组件禁用SSR
})

export default function Page() {
  return (
    <div>
      <h1>我的页面</h1>
      <HeavyComponent />
    </div>
  )
}
条件加载:
typescript
'use client'

import { useState } from 'react'
import dynamic from 'next/dynamic'

const Chart = dynamic(() => import('./chart'), { ssr: false })

export function Dashboard() {
  const [showChart, setShowChart] = useState(false)

  return (
    <div>
      <button onClick={() => setShowChart(true)}>显示图表</button>
      {showChart && <Chart />}
    </div>
  )
}

2. Code Splitting

2. 代码分割

Route-level Splitting (automatic):
app/
├── page.tsx       → Bundles: /, shared
├── about/
│   └── page.tsx   → Bundles: /about, shared
└── products/
    └── page.tsx   → Bundles: /products, shared
Component-level Splitting (with dynamic import):
typescript
const Analytics = dynamic(() => import('./analytics'))
const Comments = dynamic(() => import('./comments'))

export default function BlogPost() {
  return (
    <article>
      <h1>Post Title</h1>
      <p>Content...</p>
      <Analytics /> {/* Separate bundle */}
      <Comments />  {/* Separate bundle */}
    </article>
  )
}

路由级分割(自动):
app/
├── page.tsx       → 打包文件: /, shared
├── about/
│   └── page.tsx   → 打包文件: /about, shared
└── products/
    └── page.tsx   → 打包文件: /products, shared
组件级分割(使用动态导入):
typescript
const Analytics = dynamic(() => import('./analytics'))
const Comments = dynamic(() => import('./comments'))

export default function BlogPost() {
  return (
    <article>
      <h1>文章标题</h1>
      <p>内容...</p>
      <Analytics /> {/* 独立打包文件 */}
      <Comments />  {/* 独立打包文件 */}
    </article>
  )
}

3. Turbopack (Stable in Next.js 16)

3. Turbopack(Next.js 16中稳定)

Default: Turbopack is now the default bundler in Next.js 16.
Metrics:
  • 2–5× faster production builds
  • Up to 10× faster Fast Refresh
Opt-out (if needed):
bash
npm run build -- --webpack
Enable File System Caching (beta):
typescript
// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    turbopack: {
      fileSystemCaching: true, // Beta: Persist cache between runs
    },
  },
}

export default config
See Reference:
references/performance-optimization.md

默认: Turbopack现在是Next.js 16中的默认打包工具。
性能指标:
  • 生产构建速度提升2–5倍
  • Fast Refresh速度提升最高10倍
退出使用(如果需要):
bash
npm run build -- --webpack
启用文件系统缓存(测试版):
typescript
// next.config.ts
import type { NextConfig } from 'next'

const config: NextConfig = {
  experimental: {
    turbopack: {
      fileSystemCaching: true, // 测试版: 在多次运行之间保留缓存
    },
  },
}

export default config
参考文档:
references/performance-optimization.md

TypeScript Configuration

TypeScript配置

1. Strict Mode

1. 严格模式

Enable strict mode in
tsconfig.json
:
json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

tsconfig.json
中启用严格模式
:
json
{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

2. Path Aliases

2. 路径别名

Configure in tsconfig.json:
json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./app/*"],
      "@/components/*": ["./app/components/*"],
      "@/lib/*": ["./lib/*"],
      "@/styles/*": ["./styles/*"]
    }
  }
}
Usage:
typescript
// Instead of: import { Button } from '../../../components/button'
import { Button } from '@/components/button'

在tsconfig.json中配置:
json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./app/*"],
      "@/components/*": ["./app/components/*"],
      "@/lib/*": ["./lib/*"],
      "@/styles/*": ["./styles/*"]
    }
  }
}
使用示例:
typescript
// 替代: import { Button } from '../../../components/button'
import { Button } from '@/components/button'

3. Type-Safe Routing

3. 类型安全路由

Generate types from routes:
bash
npm run build
Usage:
typescript
import { useRouter } from 'next/navigation'

const router = useRouter()

// Type-safe routing
router.push('/posts/123') // ✅ Valid route
router.push('/invalid')   // ❌ Type error if route doesn't exist
See Reference:
references/typescript-configuration.md

从路由生成类型:
bash
npm run build
使用示例:
typescript
import { useRouter } from 'next/navigation'

const router = useRouter()

// 类型安全路由
router.push('/posts/123') // ✅ 有效路由
router.push('/invalid')   // ❌ 如果路由不存在会触发类型错误
参考文档:
references/typescript-configuration.md

Common Errors & Solutions

常见错误与解决方案

1. Error:
params
is a Promise

1. 错误:
params
is a Promise

Error:
Type 'Promise<{ id: string }>' is not assignable to type '{ id: string }'
Cause: Next.js 16 changed
params
to async.
Solution: Await
params
:
typescript
// ❌ 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
}

错误信息:
Type 'Promise<{ id: string }>' is not assignable to type '{ id: string }'
原因: Next.js 16将
params
改为异步。
解决方案: Await
params
:
typescript
// ❌ 之前
export default function Page({ params }: { params: { id: string } }) {
  const id = params.id
}

// ✅ 之后
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
}

2. Error:
searchParams
is a Promise

2. 错误:
searchParams
is a Promise

Error:
Property 'query' does not exist on type 'Promise<{ query: string }>'
Cause:
searchParams
is now async in Next.js 16.
Solution:
typescript
// ❌ 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
}

错误信息:
Property 'query' does not exist on type 'Promise<{ query: string }>'
原因: Next.js 16中
searchParams
现在是异步。
解决方案:
typescript
// ❌ 之前
export default function Page({ searchParams }: { searchParams: { query: string } }) {
  const query = searchParams.query
}

// ✅ 之后
export default async function Page({ searchParams }: { searchParams: Promise<{ query: string }> }) {
  const { query } = await searchParams
}

3. Error:
cookies()
requires await

3. 错误:
cookies()
requires await

Error:
'cookies' implicitly has return type 'any'
Cause:
cookies()
is now async in Next.js 16.
Solution:
typescript
// ❌ 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()
}

错误信息:
'cookies' implicitly has return type 'any'
原因: Next.js 16中
cookies()
现在是异步。
解决方案:
typescript
// ❌ 之前
import { cookies } from 'next/headers'

export function MyComponent() {
  const cookieStore = cookies()
}

// ✅ 之后
import { cookies } from 'next/headers'

export async function MyComponent() {
  const cookieStore = await cookies()
}

4. Error: Parallel route missing
default.js

4. 错误: Parallel route missing
default.js

Error:
Error: Parallel route @modal/login was matched but no default.js was found
Cause: Next.js 16 requires
default.js
for all parallel routes.
Solution: Add
default.tsx
files:
typescript
// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

错误信息:
Error: Parallel route @modal/login was matched but no default.js was found
原因: Next.js 16要求所有并行路由都有
default.js
解决方案: 添加
default.tsx
文件:
typescript
// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

5. Error:
revalidateTag()
requires 2 arguments

5. 错误:
revalidateTag()
requires 2 arguments

Error:
Expected 2 arguments, but got 1
Cause:
revalidateTag()
now requires a
cacheLife
argument in Next.js 16.
Solution:
typescript
// ❌ Before
revalidateTag('posts')

// ✅ After
revalidateTag('posts', 'max')

错误信息:
Expected 2 arguments, but got 1
原因: Next.js 16中
revalidateTag()
需要
cacheLife
参数。
解决方案:
typescript
// ❌ 之前
revalidateTag('posts')

// ✅ 之后
revalidateTag('posts', 'max')

6. Error: Cannot use React hooks in Server Component

6. 错误: Cannot use React hooks in Server Component

Error:
You're importing a component that needs useState. It only works in a Client Component
Cause: Using React hooks in Server Component.
Solution: Add
'use client'
directive:
typescript
// ✅ 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>
}

错误信息:
You're importing a component that needs useState. It only works in a Client Component
原因: 在Server Component中使用React钩子。
解决方案: 添加
'use client'
指令:
typescript
// ✅ 添加'use client'到顶部
'use client'

import { useState } from 'react'

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

7. Error:
middleware.ts
is deprecated

7. 错误:
middleware.ts
is deprecated

Warning:
Warning: middleware.ts is deprecated. Use proxy.ts instead.
Solution: Migrate to
proxy.ts
:
typescript
// Rename: middleware.ts → proxy.ts
// Rename function: middleware → proxy

export function proxy(request: NextRequest) {
  // Same logic
}

警告信息:
Warning: middleware.ts is deprecated. Use proxy.ts instead.
解决方案: 迁移到
proxy.ts
:
typescript
// 重命名: middleware.ts → proxy.ts
// 重命名函数: middleware → proxy

export function proxy(request: NextRequest) {
  // 逻辑保持不变
}

8. Error: Turbopack build failure

8. 错误: Turbopack build failure

Error:
Error: Failed to compile with Turbopack
Cause: Turbopack is now default in Next.js 16.
Solution: Opt out of Turbopack if incompatible:
bash
npm run build -- --webpack

错误信息:
Error: Failed to compile with Turbopack
原因: Next.js 16中Turbopack是默认打包工具。
解决方案: 如果不兼容,退出使用Turbopack:
bash
npm run build -- --webpack

9. Error: Invalid
next/image
src

9. 错误: Invalid
next/image
src

Error:
Invalid src prop (https://example.com/image.jpg) on `next/image`. Hostname "example.com" is not configured under images in your `next.config.js`
Solution: Add remote patterns in
next.config.ts
:
typescript
const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
      },
    ],
  },
}

错误信息:
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
中添加远程模式:
typescript
const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
      },
    ],
  },
}

10. Error: Cannot import Server Component into Client Component

10. 错误: Cannot import Server Component into Client Component

Error:
You're importing a Server Component into a Client Component
Solution: Pass Server Component as children:
typescript
// ❌ 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>

错误信息:
You're importing a Server Component into a Client Component
解决方案: 将Server Component作为子组件传递:
typescript
// ❌ 错误
'use client'
import { ServerComponent } from './server-component' // 错误

export function ClientComponent() {
  return <ServerComponent />
}

// ✅ 正确
'use client'

export function ClientComponent({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}

// 使用方式
<ClientComponent>
  <ServerComponent /> {/* 作为子组件传递 */}
</ClientComponent>

11. Error:
generateStaticParams
not working

11. 错误:
generateStaticParams
not working

Cause:
generateStaticParams
only works with static generation (
export const dynamic = 'force-static'
).
Solution:
typescript
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 }))
}

原因:
generateStaticParams
仅在静态生成模式下工作(
export const dynamic = 'force-static'
)。
解决方案:
typescript
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. Error:
fetch()
not caching

12. 错误:
fetch()
not caching

Cause: Next.js 16 uses opt-in caching with
"use cache"
directive.
Solution: Add
"use cache"
to component or function:
typescript
'use cache'

export async function getPosts() {
  const response = await fetch('/api/posts')
  return response.json()
}

原因: Next.js 16使用
"use cache"
指令实现可选缓存。
解决方案: 在组件或函数中添加
"use cache"
:
typescript
'use cache'

export async function getPosts() {
  const response = await fetch('/api/posts')
  return response.json()
}

13. Error: Route collision with Route Groups

13. 错误: Route collision with Route Groups

Error:
Error: Conflicting routes: /about and /(marketing)/about
Cause: Route groups create same URL path.
Solution: Ensure route groups don't conflict:
app/
├── (marketing)/about/page.tsx  → /about
└── (shop)/about/page.tsx       → ERROR: Duplicate /about
错误信息:
Error: Conflicting routes: /about and /(marketing)/about
原因: 路由组创建了相同的URL路径。
解决方案: 确保路由组不冲突:
app/
├── (marketing)/about/page.tsx  → /about
└── (shop)/about/page.tsx       → 错误: 重复的/about

Fix: Use different routes

修复: 使用不同的路由

app/ ├── (marketing)/about/page.tsx → /about └── (shop)/store-info/page.tsx → /store-info

---
app/ ├── (marketing)/about/page.tsx → /about └── (shop)/store-info/page.tsx → /store-info

---

14. Error: Metadata not updating

14. 错误: Metadata not updating

Cause: Using dynamic metadata without
generateMetadata()
.
Solution: Use
generateMetadata()
for dynamic pages:
typescript
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,
  }
}

原因: 动态页面未使用
generateMetadata()
解决方案: 动态页面使用
generateMetadata()
:
typescript
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. Error:
next/font
font not loading

15. 错误:
next/font
font not loading

Cause: Font variable not applied to HTML element.
Solution: Apply font variable to
<html>
or
<body>
:
typescript
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>
  )
}

原因: 字体变量未应用到HTML元素。
解决方案: 将字体变量应用到
<html>
<body>
:
typescript
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}> {/* ✅ 应用变量 */}
      <body>{children}</body>
    </html>
  )
}

16. Error: Environment variables not available in browser

16. 错误: Environment variables not available in browser

Cause: Server-only env vars are not exposed to browser.
Solution: Prefix with
NEXT_PUBLIC_
for client-side access:
bash
undefined
原因: 仅服务器端的环境变量不会暴露给浏览器。
解决方案: 客户端访问的变量需添加
NEXT_PUBLIC_
前缀:
bash
undefined

.env

.env

SECRET_KEY=abc123 # Server-only NEXT_PUBLIC_API_URL=https://api # Available in browser

```typescript
// 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

SECRET_KEY=abc123 # 仅服务器端可用 NEXT_PUBLIC_API_URL=https://api # 浏览器端可用

```typescript
// Server Component(两者都可用)
const secret = process.env.SECRET_KEY
const apiUrl = process.env.NEXT_PUBLIC_API_URL

// Client Component(仅公共变量可用)
const apiUrl = process.env.NEXT_PUBLIC_API_URL

17. Error: Server Action not found

17. 错误: Server Action not found

Error:
Error: Could not find Server Action
Cause: Missing
'use server'
directive.
Solution: Add
'use server'
:
typescript
// ❌ Before
export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

// ✅ After
'use server'

export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

错误信息:
Error: Could not find Server Action
原因: 缺少
'use server'
指令。
解决方案: 添加
'use server'
:
typescript
// ❌ 之前
export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

// ✅ 之后
'use server'

export async function createPost(formData: FormData) {
  await db.posts.create({ ... })
}

18. Error: TypeScript path alias not working

18. 错误: TypeScript path alias not working

Cause: Incorrect
baseUrl
or
paths
in
tsconfig.json
.
Solution: Configure correctly:
json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"],
      "@/components/*": ["./app/components/*"]
    }
  }
}
See Reference:
references/top-errors.md

原因:
tsconfig.json
中的
baseUrl
paths
配置错误。
解决方案: 正确配置:
json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"],
      "@/components/*": ["./app/components/*"]
    }
  }
}
参考文档:
references/top-errors.md

Templates Reference

模板参考

The following templates are available in
templates/
:
App Router Fundamentals:
  • app-router-async-params.tsx
    - Async params, searchParams patterns (Next.js 16)
  • parallel-routes-with-default.tsx
    - Parallel routes with required default.js
  • route-groups-example.tsx
    - Route groups organization
Cache Components (Next.js 16):
  • cache-component-use-cache.tsx
    - Cache Components with
    "use cache"
  • partial-prerendering.tsx
    - PPR with static + dynamic parts
  • revalidate-tag-cache-life.ts
    - Updated
    revalidateTag()
    API
  • server-action-update-tag.ts
    -
    updateTag()
    for read-your-writes
Server Components:
  • server-component-data-fetching.tsx
    - Data fetching patterns
  • server-component-streaming.tsx
    - Streaming with Suspense
  • server-component-composition.tsx
    - Server + Client component composition
Server Actions:
  • server-actions-form.tsx
    - Form handling with Server Actions
  • server-actions-validation.ts
    - Server Action validation with Zod
  • server-actions-optimistic.tsx
    - Optimistic updates
Route Handlers:
  • route-handler-api.ts
    - Basic CRUD API
  • route-handler-webhook.ts
    - Webhook handling
  • route-handler-streaming.ts
    - Streaming responses
Proxy & Middleware:
  • proxy-migration.ts
    - Migrate from middleware.ts to proxy.ts
  • proxy-auth.ts
    - Auth with proxy.ts
React 19.2:
  • view-transitions-react-19.tsx
    - View Transitions API
  • use-effect-event.tsx
    -
    useEffectEvent()
    pattern
  • react-compiler-example.tsx
    - React Compiler usage
Metadata:
  • metadata-config.ts
    - Static and dynamic metadata
  • sitemap.ts
    - Sitemap generation
  • robots.ts
    - robots.txt generation
Optimization:
  • image-optimization.tsx
    - next/image patterns
  • font-optimization.tsx
    - next/font patterns
  • lazy-loading.tsx
    - Dynamic imports and lazy loading
  • code-splitting.tsx
    - Code splitting strategies
TypeScript:
  • typescript-config.json
    - Recommended TypeScript configuration
  • path-aliases.tsx
    - Path alias usage
Configuration:
  • next.config.ts
    - Full Next.js configuration
  • package.json
    - Recommended dependencies for Next.js 16

以下模板在
templates/
目录中可用:
App Router基础:
  • app-router-async-params.tsx
    - 异步参数、searchParams模式(Next.js 16)
  • parallel-routes-with-default.tsx
    - 带必填default.js的并行路由
  • route-groups-example.tsx
    - 路由组组织
Cache Components(Next.js 16):
  • cache-component-use-cache.tsx
    - 使用
    "use cache"
    的Cache Components
  • partial-prerendering.tsx
    - 静态+动态部分的PPR
  • revalidate-tag-cache-life.ts
    - 更新后的
    revalidateTag()
    API
  • server-action-update-tag.ts
    - 用于读写一致性的
    updateTag()
Server Components:
  • server-component-data-fetching.tsx
    - 数据获取模式
  • server-component-streaming.tsx
    - 使用Suspense的流式渲染
  • server-component-composition.tsx
    - Server + Client组件组合
Server Actions:
  • server-actions-form.tsx
    - 使用Server Actions的表单处理
  • server-actions-validation.ts
    - 使用Zod的Server Action验证
  • server-actions-optimistic.tsx
    - 乐观更新
Route Handlers:
  • route-handler-api.ts
    - 基础CRUD API
  • route-handler-webhook.ts
    - Webhook处理
  • route-handler-streaming.ts
    - 流式响应
Proxy & Middleware:
  • proxy-migration.ts
    - 从middleware.ts迁移到proxy.ts
  • proxy-auth.ts
    - 使用proxy.ts的认证
React 19.2:
  • view-transitions-react-19.tsx
    - View Transitions API
  • use-effect-event.tsx
    -
    useEffectEvent()
    模式
  • react-compiler-example.tsx
    - React Compiler使用
元数据:
  • metadata-config.ts
    - 静态和动态元数据
  • sitemap.ts
    - 站点地图生成
  • robots.ts
    - robots.txt生成
优化:
  • image-optimization.tsx
    - next/image模式
  • font-optimization.tsx
    - next/font模式
  • lazy-loading.tsx
    - 动态导入和懒加载
  • code-splitting.tsx
    - 代码分割策略
TypeScript:
  • typescript-config.json
    - 推荐的TypeScript配置
  • path-aliases.tsx
    - 路径别名使用
配置:
  • next.config.ts
    - 完整的Next.js配置
  • package.json
    - Next.js 16的推荐依赖

Additional Resources

额外资源

Bundled References (in
references/
):
  • next-16-migration-guide.md
    - Complete migration from Next.js 15 to 16
  • cache-components-guide.md
    - Cache Components deep dive
  • proxy-vs-middleware.md
    - Proxy.ts vs middleware.ts comparison
  • async-route-params.md
    - Async params, searchParams, cookies(), headers()
  • app-router-fundamentals.md
    - App Router concepts and patterns
  • server-components-patterns.md
    - Server Components best practices
  • server-actions-guide.md
    - Server Actions patterns and validation
  • route-handlers-reference.md
    - Route Handlers API reference
  • metadata-api-guide.md
    - Metadata API complete guide
  • performance-optimization.md
    - Performance patterns and Turbopack
  • react-19-integration.md
    - React 19.2 features in Next.js
  • top-errors.md
    - 18+ common errors and solutions
Scripts:
  • scripts/check-versions.sh
    - Verify Next.js and dependency versions
External Documentation:

内置参考文档(在
references/
目录中):
  • next-16-migration-guide.md
    - 从Next.js 15到16的完整迁移指南
  • cache-components-guide.md
    - Cache Components深度解析
  • proxy-vs-middleware.md
    - Proxy.ts vs middleware.ts对比
  • async-route-params.md
    - 异步参数、searchParams、cookies()、headers()
  • app-router-fundamentals.md
    - App Router概念和模式
  • server-components-patterns.md
    - Server Components最佳实践
  • server-actions-guide.md
    - Server Actions模式和验证
  • route-handlers-reference.md
    - Route Handlers API参考
  • metadata-api-guide.md
    - 元数据API完整指南
  • performance-optimization.md
    - 性能优化模式和Turbopack
  • react-19-integration.md
    - Next.js中的React 19.2特性
  • top-errors.md
    - 18+常见错误和解决方案
脚本:
  • scripts/check-versions.sh
    - 验证Next.js和依赖版本
外部文档:

Version Compatibility

版本兼容性

PackageMinimum VersionRecommended
Next.js16.0.016.0.0+
React19.2.019.2.0+
Node.js20.9.020.9.0+
TypeScript5.1.05.7.0+
Turbopack(built-in)Stable
Check Versions:
bash
./scripts/check-versions.sh

最低版本推荐版本
Next.js16.0.016.0.0+
React19.2.019.2.0+
Node.js20.9.020.9.0+
TypeScript5.1.05.7.0+
Turbopack(内置)稳定版
检查版本:
bash
./scripts/check-versions.sh

Token Efficiency

Token效率

Estimated Token Savings: 65-70%
Without Skill (manual setup from docs):
  • Read Next.js 16 migration guide: ~5k tokens
  • Read App Router docs: ~8k tokens
  • Read Server Actions docs: ~4k tokens
  • Read Metadata API docs: ~3k tokens
  • Trial-and-error fixes: ~8k tokens
  • Total: ~28k tokens
With Skill:
  • Load skill: ~8k tokens
  • Use templates: ~2k tokens
  • Total: ~10k tokens
  • Savings: ~18k tokens (~64%)
Errors Prevented: 18+ common mistakes = 100% error prevention

预估Token节省: 65-70%
不使用本技能(从文档手动设置):
  • 阅读Next.js 16迁移指南: ~5k tokens
  • 阅读App Router文档: ~8k tokens
  • 阅读Server Actions文档: ~4k tokens
  • 阅读元数据API文档: ~3k tokens
  • 反复试错修复: ~8k tokens
  • 总计: ~28k tokens
使用本技能:
  • 加载技能: ~8k tokens
  • 使用模板: ~2k tokens
  • 总计: ~10k tokens
  • 节省: ~18k tokens (~64%)
避免的错误: 18+常见错误 = 100%错误预防

Maintenance

维护

Last Verified: 2025-10-24 Next Review: 2026-01-24 (Quarterly) Maintainer: Jezweb | jeremy@jezweb.net Repository: https://github.com/jezweb/claude-skills
Update Triggers:
  • Next.js major/minor releases
  • React major releases
  • Breaking changes in APIs
  • New Turbopack features
Version Check:
bash
cd skills/nextjs
./scripts/check-versions.sh

End of SKILL.md
最后验证时间: 2025-10-24 下次审核时间: 2026-01-24(每季度) 维护者: Jezweb | jeremy@jezweb.net 仓库: https://github.com/jezweb/claude-skills
更新触发条件:
  • Next.js大版本/小版本发布
  • React大版本发布
  • API中的重大变更
  • Turbopack新特性
版本检查:
bash
cd skills/nextjs
./scripts/check-versions.sh

SKILL.md结束