Pages Router → App Router
The App Router can be adopted incrementally — app/ and pages/ coexist in the same project. Move routes one at a time, converting getServerSideProps/getStaticProps to Server Components with fetch, and _app/_document to a root layout.
Last verified · Updated May 22, 2026
Adopt the App Router incrementally: app/ and pages/ coexist in the same Next.js project, so you migrate route by route. Convert getServerSideProps/getStaticProps to Server Components with fetch, and replace _app/_document with a root layout.
Incremental adoption
You do not rewrite everything at once. Next.js routes a path through app/ if it exists there and otherwise falls back to pages/, so you can move one route, ship it, and repeat. Keep both routers until the last page is migrated.
Key routing and data differences
- File-based routing: pages/about.tsx becomes app/about/page.tsx; dynamic [id] segments still apply.
- getServerSideProps → Server Component with await fetch() (no cache) or a dynamic route.
- getStaticProps / getStaticPaths → Server Component fetch with caching + generateStaticParams.
- _app.tsx and _document.tsx → a single root app/layout.tsx with <html> and <body>.
- API routes in pages/api/* → Route Handlers in app/**/route.ts.
Pages Router vs App Router
| Pages Router | App Router |
|---|---|
| pages/index.tsx | app/page.tsx |
| getServerSideProps | async Server Component + fetch (no-store) |
| getStaticProps / getStaticPaths | fetch (cached) + generateStaticParams |
| _app.tsx / _document.tsx | app/layout.tsx (root layout) |
| pages/api/route.ts | app/api/route/route.ts (Route Handler) |
| next/head | metadata export / generateMetadata |
Because app/ and pages/ run side by side, an unfinished migration still ships. Migrate, verify, and merge one route group at a time rather than holding a long-lived branch.
Migrate the single Pages Router route <route> to the App Router. Create the matching app/ segment, convert getServerSideProps/getStaticProps to a Server Component using fetch (choose no-store vs cached based on the original), move <Head> content into a metadata export, and leave the rest of pages/ untouched. Run next build and the route's tests, then report before moving to the next route.
Safety: Migrate one route at a time. Never delete the pages/ equivalent until the app/ route is verified in a build.
Per-route PR review checklist
- The app/ route renders and the old pages/ route was removed only after verification
- Data fetching uses the correct caching (no-store vs force-cache) for the original behavior
- Head/metadata moved to the metadata API
- Shared layout/state lives in the root layout, not duplicated per route
- next build passes with both routers present
Rollback strategy
- Each route is its own commit; revert a single route without touching the rest.
- Keep the pages/ version until the app/ version has shipped and been verified.
- If a route blocks on a Server Component incompatibility, leave it in pages/ and continue with others.
Related paths
Official sources
Backs the breaking-change and migration-step claims.
Backs the breaking-change and migration-step claims.
Copy-ready AI prompts
Structured prompts for an AI coding assistant. Inspect first, then execute incrementally, and keep a human in the review loop.
You are helping migrate a Next.js codebase from the Pages Router to the App Router. Do not edit files yet. First inspect the repository and report: 1. The exact next, react, and react-dom versions in package.json and the lockfile. 2. Whether the app uses the App Router (app/), the Pages Router (pages/), or both. 3. Synchronous usage of cookies(), headers(), draftMode(), and any page/layout/route that reads params or searchParams synchronously. 4. fetch() calls and GET Route Handlers that rely on the old default caching behavior. 5. Usage of the standalone @next/font package and any next.config edits that may break. 6. The build, lint, and test commands. Return: a migration risk summary, the files most likely to break, a suggested migration order, the commands to run before editing, and any questions that need human confirmation.
Safety: Inspection only. The agent must not modify files in this step.
Works with Claude Code, Cursor, GitHub Copilot
Migrate this codebase from the Pages Router to the App Router, one concern at a time. Work in this order and pause for review after each: (1) bump next, react, and react-dom, (2) run the official upgrade CLI (npx @next/codemod@canary upgrade latest), (3) await the now-async request APIs (cookies/headers/draftMode/params/searchParams) flagged during inspection, (4) decide caching intent per fetch/Route Handler and add cache: 'force-cache' or dynamic config where the old default was relied on, (5) fix type errors. After each step run the project's typecheck, lint, build, and tests, and report results before continuing. Do not refactor unrelated code.
Safety: Apply changes incrementally and keep each step reviewable. Never bundle unrelated refactors.
Works with Claude Code, Cursor, GitHub Copilot
Test plan
Commands
npx tsc --noEmitnpm run lintnpm run buildnpm test -- --watch=false
Manual checks
- For each migrated route, compare rendered output and metadata against the old pages/ version.
- Confirm data freshness: no-store routes stay dynamic, cached routes stay static.
- Verify shared providers from the old _app.tsx still wrap every app/ route.
Regression risks
- Data that was cached via getStaticProps becoming dynamic under fetch defaults.
- Lost <Head> metadata when not ported to the metadata API.
- Client-only components rendered as Server Components without 'use client'.
Acceptance criteria
- Every targeted route is served by the App Router and the old pages/ file is removed.
- next build, typecheck, lint, and tests pass.
- Caching and metadata match the original Pages Router behavior.