Prompt-to-PR: Migrate Next.js 14 to 16
Step-by-step SOP for migrating a Next.js 14 App Router project to Next.js 16 — Turbopack, React 19, async APIs, and caching changes covered.
CursorClaude CodeCodexWindsurf Next.jsTypeScript
Next.js 16 ships React 19, async params and searchParams, overhauled fetch caching, and Turbopack as the default dev bundler. This playbook keeps the agent focused on breaking changes and prevents it from rewriting working code.
1. Requirement
Upgrade next from 14.x to 16.x (and react/react-dom to 19.x) with zero functionality regressions. Address every breaking change surfaced by the official codemod and any residual issues not caught by it.
2. First Prompt
Migrate this project from Next.js 14 to Next.js 16. Follow these steps exactly.
Step 1 — run the official codemod: npx @next/codemod@latest upgrade latest --yes
Step 2 — manual fixes the codemod does not cover: a. `params` and `searchParams` in page.tsx/layout.tsx files are now Promises. Await them: `const { id } = await params;` Do NOT destructure params in the function signature. b. `cookies()`, `headers()`, `draftMode()` are now async. Add `await` before every call. c. `fetch()` is no longer cached by default in Route Handlers. Where caching is intentional, add `{ next: { revalidate: N } }`. d. Remove any `export const dynamic = 'force-dynamic'` that is now the default. e. Replace `<Image>` with the new `onLoad` prop signature if present.
Step 3 — update package.json: "next": "^16.0.0" "react": "^19.0.0" "react-dom": "^19.0.0" "@types/react": "^19.0.0" "@types/react-dom": "^19.0.0"
Do not change any business logic, UI, or database code.List every file you changed and why.3. Expected File Changes
package.json (next, react, react-dom, @types/react*)src/app/**/page.tsx (await params / searchParams)src/app/**/layout.tsx (await params where used)src/app/api/**/route.ts (await cookies/headers; fetch cache opts)src/middleware.ts (if it uses deprecated config keys)next.config.ts (remove deprecated options)4. Review Checklist
package.jsonpinsnextto^16.0.0and React to^19.0.0.- Every page/layout that destructures
paramsnow awaits it first. - No synchronous
cookies()orheaders()calls remain in Server Components. fetchcalls that previously relied on implicit caching have an explicitrevalidateorno-storeoption.next.config.tshas no deprecatedexperimental.appDirorswcMinifykeys.- TypeScript compiles with
bun tsc --noEmit— zero errors. - The agent did not rewrite any UI components or business logic.
5. Test Commands
# Install updated depsbun install
# Type-checkbun tsc --noEmit
# Dev build (Turbopack default in Next.js 16)bun dev
# Production build — catches async-params errors at compile timebun run build
# Run existing test suitebun test6. Common Failures
params.idused before await — TypeScript error:Property 'id' does not exist on type 'Promise<...>'. The agent sometimes awaitsparamsin one file and not another.cookies()not awaited — runtime error:cookies() was called outside of a Server Component. Addawait.- Turbopack incompatible webpack plugin —
next deverrors on a customwebpack()config. Turbopack ignores webpack plugins; migrate or conditionally gate them. @types/reactversion conflict — peer-dep mismatch between old component libraries and React 19 types. Pin@types/reactto 19 and override if needed.useFormStateremoved — replaced byuseActionStatefromreact. The codemod usually catches this but confirm.
7. Fix Prompt
TypeScript reports: "Property 'slug' does not exist on type'Promise<{ slug: string }>'" in src/app/blog/[slug]/page.tsx.
The page function signature must be: export default async function Page({ params }: { params: Promise<{ slug: string }> })
Then at the top of the function body: const { slug } = await params;
Apply the same fix to every other page or layout that destructures paramswithout awaiting. List every file changed.8. PR Description
## Chore: Migrate Next.js 14 → 16 + React 19
**Breaking changes addressed**:- `params` / `searchParams` are now `Promise`s — awaited in all pages/layouts- `cookies()` / `headers()` are now async — awaited in all Server Components- Fetch caching defaults changed — explicit `revalidate` added where needed- Removed deprecated `next.config.ts` keys (`swcMinify`, `experimental.appDir`)
**Tooling**: dev server now uses Turbopack by default (`next dev --turbopack`).
Run `bun run build` to confirm zero type errors before merging.