Token导航 LogoToken导航

Agent Skill · 研究检索

nextjs(Next.js 开发)

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

nextjs 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为接触敏感数据;许可证为 MIT,暂无第三方扫描结果,按安装量在研究检索类的 73,675 个 Skill 里排第 46,860。

总安装 759周安装 31GitHub Stars 公开资料未说明下载 246核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:nextjs(Next.js 开发)
来源仓库:https://github.com/jackspace/claudeskillz
仓库路径:skills/nextjs
安装命令:
npx skills add jackspace/claudeskillz --skill "nextjs"
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

AgentSkills.tonpx skills
npx skills add jackspace/claudeskillz --skill "nextjs"

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

辅助 Next.js 前端项目开发,涵盖页面、组件与样式实现。适合快速原型搭建、UI 重构或响应式布局适配场景。生成 React/Vue 组件代码并给出路由与构建建议。修改生产环境页面前应本地预览,避免破坏现有功能与 SEO。nextjs 属于研究检索类 Skill,可作为该场景下的辅助能力补充。

来源仓库内路径:skills/nextjs

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add jackspace/claudeskillz --skill "nextjs";命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

nextjs 怎么安装?

在终端执行 npx skills add jackspace/claudeskillz --skill "nextjs"。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

nextjs 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

nextjs 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

nextjs 是免费的吗?

来源标注的许可证是 MIT。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

nextjs 用的人多吗?

公开数据是累计安装 759 次,近一周安装 31 次,下载 246 次。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

nextjs 安全吗?

没有查到第三方扫描结果,安全性无法从公开资料判断,安装前请自行审查源码、依赖和命令行为。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 许可证明确为 MIT,商用和分发边界好判断。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 没有第三方扫描结果,安全性只能靠自己读源码判断。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 要求有安全扫描结论才肯安装的团队。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
nextjs

Next.js 开发 · 本页

759—接触敏感数据MIT未收录

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

name
nextjs
description
|
Keywords
Next.js 16, Next.js App Router, Next.js Pages Router, Server Components, React Server Components, Server Actions, Cache Components, use cache, Next.js 16 breaking changes, async params nextjs, proxy.ts migration, React 19.2, Next.js metadata, Next.js SEO, generateMetadata, static generation, dynamic rendering, streaming SSR, Suspense, parallel routes, intercepting routes, route groups, Next.js middleware, Next.js API routes, Route Handlers, revalidatePath, revalidateTag, next/navigation, useSearchParams, turbopack, next.config
license
MIT
metadata
version
1.0.0
last_verified
2025-10-24
nextjs_version
16.0.0
react_version
19.2.0
node_version
20.9+
author
Jezweb
repository
https://github.com/jezweb/claude-skills
production_tested
true
token_savings
65-70%
errors_prevented
18+
allowed-tools
["Read", "Write", "Edit", "Bash", "Glob", "Grep"]

Next.js App Router - Production Patterns

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


Table of Contents

  1. When to Use This Skill
  2. When NOT to Use This Skill
  3. Next.js 16 Breaking Changes
  4. Cache Components & Caching APIs
  5. Server Components
  6. Server Actions
  7. Route Handlers
  8. Proxy vs Middleware
  9. Parallel Routes & Route Groups
  10. React 19.2 Features
  11. Metadata API
  12. Image & Font Optimization
  13. Performance Patterns
  14. TypeScript Configuration
  15. Common Errors & Solutions
  16. Templates Reference
  17. Additional Resources

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)

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)

Next.js 16 Breaking Changes

IMPORTANT: Next.js 16 introduces multiple breaking changes. Read this section carefully if migrating from Next.js 15 or earlier.

1. Async Route Parameters (BREAKING)

Breaking Change: params, searchParams, cookies(), headers(), draftMode() are now async and must be awaited.

Before (Next.js 15):

// ❌ 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):

// ✅ 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:

// ❌ 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


2. Middleware → Proxy Migration (BREAKING)

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):

// 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):

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


3. Parallel Routes Require default.js (BREAKING)

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:

// 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):

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


4. Removed Features (BREAKING)

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).

5. Version Requirements (BREAKING)

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:

node --version    # Should be 20.9+
npm --version     # Should be 10+
npx next --version # Should be 16.0.0+

Upgrade Node.js:

# Using nvm
nvm install 20
nvm use 20
nvm alias default 20

# Using Homebrew (macOS)
brew install node@20

# Using apt (Ubuntu/Debian)
sudo apt update
sudo apt install nodejs npm

6. Image Defaults Changed (BREAKING)

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):

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


Cache Components & Caching APIs

NEW in Next.js 16: Cache Components introduce opt-in caching with the "use cache" directive, replacing implicit caching from Next.js 15.

1. Overview

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

2. "use cache" Directive

Syntax: Add "use cache" at the top of a Server Component, function, or route handler.

Component-level caching:

// 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:

// 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:

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


3. Partial Prerendering (PPR)

PPR allows caching static parts of a page while rendering dynamic parts on-demand.

Pattern:

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


4. revalidateTag() - Updated API

BREAKING CHANGE: revalidateTag() now requires a second argument (cacheLife profile) for stale-while-revalidate behavior.

Before (Next.js 15):

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):

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:

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:

'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


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

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:

'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


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

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:

'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


Server Components

Server Components are React components that render on the server. They enable efficient data fetching, reduce client bundle size, and improve performance.

1. Server Component Basics

Default Behavior: All components in the App Router are Server Components by default (unless marked with 'use client').

Example:

// 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.)

2. Data Fetching in Server Components

Pattern: Use async/await directly in component body.

// 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:

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):

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


3. Streaming with Suspense

Pattern: Wrap slow components in <Suspense> to stream content as it loads.

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


4. Server 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.

// 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 Actions

Server Actions are asynchronous functions that run on the server. They enable server-side mutations, form handling, and data revalidation.

1. Server Action Basics

Definition: Add 'use server' directive to create a Server Action.

File-level Server Actions:

// 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:

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


2. Form Handling

Basic Form:

// 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):

'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:

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


3. Error Handling

Pattern: Return error objects from Server Actions, handle in Client Components.

Server Action:

// 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:

'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>
  )
}

4. Optimistic Updates

Pattern: Show UI update immediately, then sync with server.

'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


Route Handlers

Route Handlers are server-side API endpoints in the App Router. They replace API Routes from the Pages Router.

1. Basic Route Handler

File: app/api/hello/route.ts

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


2. Dynamic Routes

File: app/api/posts/[id]/route.ts

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' })
}

3. Search Params

URL: /api/posts?tag=javascript&limit=10

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

Pattern: Handle incoming webhooks from third-party services.

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


Proxy vs Middleware

Next.js 16 introduces proxy.ts to replace 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.

Migration

Before (middleware.ts):

// 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):

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


Parallel Routes & Route Groups

1. Parallel Routes

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:

// 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):

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


2. Route Groups

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


React 19.2 Features

Next.js 16 integrates React 19.2, which includes new features from React Canary.

1. View Transitions

Use Case: Smooth animations between page transitions.

'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:

/* 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


2. useEffectEvent() (Experimental)

Use Case: Extract non-reactive logic from useEffect.

'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.


3. React Compiler (Stable)

Use Case: Automatic memoization without useMemo, useCallback.

Enable in next.config.ts:

import type { NextConfig } from 'next'

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

export default config

Install Plugin:

npm install babel-plugin-react-compiler

Example (no manual memoization needed):

'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


Metadata API

The Metadata API provides type-safe SEO and social sharing metadata.

1. Static Metadata

Pattern: Export metadata object from page or layout.

// 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>
}

2. Dynamic Metadata

Pattern: Export generateMetadata async function.

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

File: app/sitemap.ts

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


Image & Font Optimization

1. next/image

Basic Usage:

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:

<Image
  src="/hero.jpg"
  alt="Hero"
  fill
  style={{ objectFit: 'cover' }}
  sizes="(max-width: 768px) 100vw, 50vw"
/>

Remote Images (configure in next.config.ts):

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


2. next/font

Google Fonts:

// 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:

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


Performance Patterns

1. Lazy Loading

Component Lazy Loading:

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:

'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>
  )
}

2. Code Splitting

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):

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>
  )
}

3. Turbopack (Stable in 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):

npm run build -- --webpack

Enable File System Caching (beta):

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


TypeScript Configuration

1. Strict Mode

Enable strict mode in tsconfig.json:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  }
}

2. Path Aliases

Configure in tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./app/*"],
      "@/components/*": ["./app/components/*"],
      "@/lib/*": ["./lib/*"],
      "@/styles/*": ["./styles/*"]
    }
  }
}

Usage:

// Instead of: import { Button } from '../../../components/button'
import { Button } from '@/components/button'

3. Type-Safe Routing

Generate types from routes:

npm run build

Usage:

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


Common Errors & Solutions

1. Error: 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:

// ❌ 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
}

2. Error: 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:

// ❌ 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
}

3. Error: cookies() requires await

Error:

'cookies' implicitly has return type 'any'

Cause: cookies() is now async in Next.js 16.

Solution:

// ❌ 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()
}

4. Error: 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:

// app/@modal/default.tsx
export default function ModalDefault() {
  return null
}

5. Error: revalidateTag() requires 2 arguments

Error:

Expected 2 arguments, but got 1

Cause: revalidateTag() now requires a cacheLife argument in Next.js 16.

Solution:

// ❌ Before
revalidateTag('posts')

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

6. Error: 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:

// ✅ 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>
}

7. Error: middleware.ts is deprecated

Warning:

Warning: middleware.ts is deprecated. Use proxy.ts instead.

Solution: Migrate to proxy.ts:

// Rename: middleware.ts → proxy.ts
// Rename function: middleware → proxy

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

8. Error: 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:

npm run build -- --webpack

9. Error: 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:

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

10. Error: Cannot import Server Component into Client Component

Error:

You're importing a Server Component into a Client Component

Solution: Pass Server Component as children:

// ❌ 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>

11. Error: generateStaticParams not working

Cause: generateStaticParams only works with static generation (export const dynamic = 'force-static').

Solution:

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

Cause: Next.js 16 uses opt-in caching with "use cache" directive.

Solution: Add "use cache" to component or function:

'use cache'

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

13. Error: 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

# Fix: Use different routes
app/
├── (marketing)/about/page.tsx     → /about
└── (shop)/store-info/page.tsx     → /store-info

14. Error: Metadata not updating

Cause: Using dynamic metadata without generateMetadata().

Solution: Use generateMetadata() for dynamic pages:

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

Cause: Font variable not applied to HTML element.

Solution: Apply font variable to <html> or <body>:

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>
  )
}

16. Error: 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:

# .env
SECRET_KEY=abc123                  # Server-only
NEXT_PUBLIC_API_URL=https://api    # Available in browser
// 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

17. Error: Server Action not found

Error:

Error: Could not find Server Action

Cause: Missing 'use server' directive.

Solution: Add 'use server':

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

// ✅ After
'use server'

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

18. Error: TypeScript path alias not working

Cause: Incorrect baseUrl or paths in tsconfig.json.

Solution: Configure correctly:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"],
      "@/components/*": ["./app/components/*"]
    }
  }
}

See Reference: 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

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:

  • Next.js 16 Blog: https://nextjs.org/blog/next-16
  • Next.js Docs: https://nextjs.org/docs
  • React Docs: https://react.dev
  • Context7 MCP: Use /websites/nextjs for latest Next.js reference

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:

./scripts/check-versions.sh

Token Efficiency

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


Maintenance

Last Verified: 2025-10-24 Next Review: 2026-01-24 (Quarterly) Maintainer: Jezweb | [email protected] 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:

cd skills/nextjs
./scripts/check-versions.sh

End of SKILL.md

平台分布

Claude Code

27.25%
按下载量换算67

Antigravity

24.61%
按下载量换算61

Gemini CLI

19.69%
按下载量换算48

windsurf

13.99%
按下载量换算34

OpenCode

8.39%
按下载量换算21

Cursor

3.74%
按下载量换算9

安全审计

暂无安全审计结果可展示。

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills