Next.js 16 no longer caches fetch() by default — add { cache: 'force-cache' } where you relied on caching
Use "use cache" directive for fine-grained caching instead of route segment config
Review generateStaticParams behavior — dynamic pages are no longer force-static by default
6. Build and Test
npm run build
npx playwright test
7. Deploy and Monitor
Check deployment logs after the first production deploy
Watch for hydration mismatches caused by client/server content differences
Monitor Core Web Vitals for regressions
Common Issues
TypeScript errors on params: ensure you're using Promise<> wrapper and await
Hydration mismatches: often caused by ThemeToggle or other client components that read browser state — use useSyncExternalStore for safe SSR
Missing data: check if you relied on default fetch caching that is now opt-in
Raw content
Copy this into your project — e.g. .instructions.md, .agent.md, or SKILL.md
## Prerequisites
- Node.js 18.18+ (recommended: 20+)
- Current app on Next.js 14 or 15
## Migration Steps
### 1. Upgrade Dependencies
```bash
npm install next@latest react@latest react-dom@latest
npm install -D eslint-config-next@latest @types/react@latest @types/react-dom@latest
```
### 2. Run the Next.js Codemod
```bash
npx @next/codemod@latest upgrade
```
This handles many automatic transformations including async API migrations.
### 3. Fix Async Route APIs
`params`, `searchParams`, `cookies()`, and `headers()` are now async. Update all route components:
```tsx
// Before (Next.js 14/15)
export default function Page({ params }: { params: { slug: string } }) {
return <div>{params.slug}</div>
}
// After (Next.js 16)
export default async function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
return <div>{slug}</div>
}
```
### 4. Update cookies() and headers()
```tsx
// Before
const cookieStore = cookies()
const token = cookieStore.get('token')
// After
const cookieStore = await cookies()
const token = cookieStore.get('token')
```
### 5. Review Caching Changes
- Next.js 16 no longer caches `fetch()` by default — add `{ cache: 'force-cache' }` where you relied on caching
- Use `"use cache"` directive for fine-grained caching instead of route segment config
- Review `generateStaticParams` behavior — dynamic pages are no longer force-static by default
### 6. Build and Test
```bash
npm run build
npx playwright test
```
### 7. Deploy and Monitor
- Check deployment logs after the first production deploy
- Watch for hydration mismatches caused by client/server content differences
- Monitor Core Web Vitals for regressions
## Common Issues
- **TypeScript errors on params**: ensure you're using `Promise<>` wrapper and `await`
- **Hydration mismatches**: often caused by `ThemeToggle` or other client components that read browser state — use `useSyncExternalStore` for safe SSR
- **Missing data**: check if you relied on default `fetch` caching that is now opt-in