Next.js App Router - Production Patterns
Version: Next.js 16.0.3
React Version: 19.2.0
Node.js: 20.9+
Last Verified: 2025-11-21
Table of Contents
- When to Use This Skill
- When NOT to Use This Skill
- Next.js 16 Breaking Changes
- Cache Components & Caching APIs
- Server Components
- Server Actions
- Route Handlers
- React 19.2 Features
- Metadata API
- Image & Font Optimization
- Top 5 Critical Errors
- Performance Patterns
- TypeScript Configuration
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 directive (NEW in Next.js 16)
- New caching APIs: , , (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 ( replaces in Next.js 16)
- Async route params (, , , now async)
- Parallel routes with default.js (breaking change in Next.js 16)
- React 19.2 features (View Transitions, , React Compiler)
- Metadata API (SEO, Open Graph, Twitter Cards, sitemaps)
- Image optimization ( with updated defaults in Next.js 16)
- Performance optimization (lazy loading, code splitting, PPR, ISR)
When NOT to Use This Skill
Do NOT use this skill for:
- Cloudflare Workers deployment → Use skill instead
- Pages Router patterns → This skill covers App Router ONLY (Pages Router is legacy)
- Authentication libraries → Use , , or other auth-specific skills
- Database integration → Use , , or database-specific skills
- UI component libraries → Use skill for Tailwind + shadcn/ui
- State management → Use , skills
- Form libraries → Use skill
Next.js 16 Breaking Changes
CRITICAL: Next.js 16 has multiple breaking changes. For detailed migration steps, see
references/next-16-migration-guide.md
.
| Breaking Change | Before | After |
|---|
| Async params | | const { slug } = await params
|
| Async headers | sync | |
| Middleware | | (renamed) |
| Parallel routes | optional | required |
| Caching | Auto-cached fetch | Opt-in with |
| revalidateTag() | 1 argument | 2 arguments (tag + cacheLife) |
| Node.js | 18.x+ | 20.9+ required |
| React | 18.x | 19.2+ required |
Quick Fix for Async Params:
typescript
// ✅ Next.js 16 pattern
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
return <div>{id}</div>
}
Codemod:
bunx @next/codemod@canary upgrade latest
See:
references/next-16-migration-guide.md
for complete migration guide with examples.
Cache Components & Caching APIs
"use cache" Directive (NEW in Next.js 16)
typescript
'use cache'
export async function BlogPosts() {
const posts = await db.posts.findMany()
return posts.map(post => <article key={post.id}>{post.title}</article>)
}
Caching APIs Summary
| API | Purpose | Example |
|---|
| Opt-in component/function caching | at top |
| Invalidate by tag | revalidateTag('posts', 'max')
|
| Update cache without revalidation | updateTag('posts', newData)
|
| Refresh current page | |
| Invalidate by path | |
PPR (Partial Prerendering)
typescript
// next.config.ts
const config = { experimental: { ppr: true } }
// page.tsx
export const experimental_ppr = true
export default function Page() {
return (
<>
<StaticHeader />
<Suspense fallback={<Skeleton />}>
<DynamicContent />
</Suspense>
</>
)
}
See:
references/caching-apis.md
for complete caching API reference with ISR, tag-based revalidation, and advanced patterns.
Server Components
Server Components are the default in App Router. They run on the server and can fetch data, access databases, and keep logic server-side.
typescript
// app/posts/page.tsx (Server Component by default)
export default async function PostsPage() {
const posts = await db.posts.findMany()
return <div>{posts.map(p => <article key={p.id}>{p.title}</article>)}</div>
}
Streaming with Suspense
typescript
import { Suspense } from 'react'
export default function Page() {
return (
<div>
<Header />
<Suspense fallback={<Skeleton />}>
<Posts />
</Suspense>
</div>
)
}
Server vs Client Components
| Server Components | Client Components |
|---|
| Data fetching, DB access | Interactivity (onClick) |
| Sensitive logic | React hooks (useState) |
| Large dependencies | Browser APIs |
| Static content | Real-time updates |
Client Component (requires
):
typescript
'use client'
import { useState } from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
Server Actions
Server Actions are async functions that run on the server, callable from Client or Server Components.
Basic Server Action
typescript
// app/actions.ts
'use server'
import { revalidatePath } from 'next/cache'
export async function createPost(formData: FormData) {
const title = formData.get('title') as string
await db.posts.create({ data: { title } })
revalidatePath('/posts')
}
Form Handling
typescript
// Server Component Form (simplest)
import { createPost } from './actions'
export default function NewPostPage() {
return (
<form action={createPost}>
<input name="title" required />
<button type="submit">Create</button>
</form>
)
}
Available Patterns
| Pattern | Use Case | Reference |
|---|
| Client Form with Loading | useFormState + useFormStatus | templates/server-action-form.tsx
|
| Error Handling | Return { error } or { success } | references/server-actions-patterns.md
|
| Optimistic Updates | useOptimistic hook | references/server-actions-patterns.md
|
| File Upload | FormData + blob storage | references/server-actions-patterns.md
|
| Redirect After Action | redirect() function | references/server-actions-patterns.md
|
See:
references/server-actions-patterns.md
for error handling, optimistic updates, file uploads, and advanced patterns.
Route Handlers
Route Handlers are the App Router equivalent of API Routes.
typescript
// app/api/posts/route.ts
export async function GET(request: Request) {
const posts = await db.posts.findMany()
return Response.json({ posts })
}
export async function POST(request: Request) {
const body = await request.json()
const post = await db.posts.create({ data: body })
return Response.json({ post }, { status: 201 })
}
Dynamic Routes (with async params):
typescript
// app/api/posts/[id]/route.ts
export async function GET(
request: Request,
{ params }: { params: Promise<{ id: string }> }
) {
const { id } = await params // Await in Next.js 16
const post = await db.posts.findUnique({ where: { id } })
return post ? Response.json({ post }) : Response.json({ error: 'Not found' }, { status: 404 })
}
See:
templates/route-handler-api.ts
for search params, webhooks, and streaming patterns.
React 19.2 Features
| Feature | Usage |
|---|
| React Compiler | experimental: { reactCompiler: true }
- Auto-memoization |
| View Transitions | + |
| useEffectEvent | Stable event handlers without deps |
Metadata API
typescript
// Static metadata
export const metadata: Metadata = {
title: 'My Blog',
description: 'A blog about Next.js',
openGraph: { title: 'My Blog', images: ['/og-image.jpg'] },
}
// Dynamic metadata (await params in Next.js 16)
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
const post = await db.posts.findUnique({ where: { id } })
return { title: post.title, description: post.excerpt }
}
Image & Font Optimization
typescript
// next/image
import Image from 'next/image'
<Image src="/profile.jpg" alt="Profile" width={500} height={500} priority />
// next/font
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' })
<html className={inter.variable}>
Remote images: Configure
in
.
Top 5 Critical Errors
Error 1: is a Promise
Error:
Type 'Promise<{ id: string }>' is not assignable to type '{ id: string }'
Solution: Await params in Next.js 16:
typescript
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params
}
Error 2: is deprecated
Warning:
middleware.ts is deprecated. Use proxy.ts instead.
Solution: Rename file and function:
typescript
// Rename: middleware.ts → proxy.ts
// Rename function: middleware → proxy
export function proxy(request: NextRequest) {
// Same logic
}
Error 3: Parallel route missing
Error:
Parallel route @modal was matched but no default.js was found
Solution: Add default.tsx:
typescript
// app/@modal/default.tsx
export default function ModalDefault() {
return null
}
Error 4: Cannot use React hooks in Server Component
Error:
You're importing a component that needs useState. It only works in a Client Component
typescript
'use client'
import { useState } from 'react'
export function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(count + 1)}>{count}</button>
}
Error 5: not caching
Cause: Next.js 16 uses opt-in caching with
.
typescript
'use cache'
export async function getPosts() {
const response = await fetch('/api/posts')
return response.json()
}
See All 18 Errors:
references/error-catalog.md
Performance Patterns
| Pattern | Usage |
|---|
| Lazy Loading | const HeavyComp = dynamic(() => import('./Heavy'), { ssr: false })
|
| Code Splitting | Automatic per route - each gets own bundle |
| Turbopack | Default in Next.js 16, opt out with flag |
| PPR | experimental: { ppr: true }
+ boundaries |
TypeScript Configuration
json
{
"compilerOptions": {
"strict": true,
"baseUrl": ".",
"paths": { "@/*": ["./*"] }
}
}
When to Load References
| Reference | Load When... |
|---|
next-16-migration-guide.md
| Migrating from Next.js 15, async params errors, proxy.ts setup |
server-actions-patterns.md
| Error handling, optimistic updates, file uploads, advanced forms |
| ISR, tag-based revalidation, updateTag(), refresh(), PPR details |
| Debugging any Next.js error, comprehensive error solutions |
| Quick fixes for the 5 most common Next.js errors |
Bundled Resources
| Type | Files |
|---|
| References | , , next-16-migration-guide.md
, server-actions-patterns.md
, |
| Templates | , , , cache-component-use-cache.tsx
, parallel-routes-with-default.tsx
, |
Related Skills
| Skill | Purpose |
|---|
| Deploy to Cloudflare Workers |
| Styling |
| Authentication |
| Database |
| Forms |
| Client state |
Version: Next.js 16.0.0 | React 19.2.0 | Node.js 20.9+ | TypeScript 5.3+
Production Tested: E-commerce, SaaS, content sites | Token Savings: 65-70%