Next.js

Verified against Claude Code · 2026-07-19

Turn a Pages Router codebase into a phased App Router migration, not a risky rewrite

Produces a route-by-route migration plan that runs Pages Router and App Router side by side, converting data-fetching methods and shared layout as it goes.

Claude CodeCursor 2.1GitHub Copilot

The prompt

Ready to copy — highlighted parts are example details you can swap.

<context>
Current pages/ directory structure: pages/index.tsx, pages/blog/[slug].tsx (getStaticProps), pages/dashboard.tsx (getServerSideProps, behind auth), pages/api/checkout.ts
Data-fetching methods currently used and where: getStaticProps on the blog, getServerSideProps on the dashboard, getInitialProps on the legacy account page
Shared layout/elements currently in _app.tsx / _document.tsx: A ThemeProvider, a global Header/Footer, and a custom <Html lang> in _document.tsx
</context>

<task>
Produce a phased migration plan from the Pages Router to the App Router for this codebase. Pages Router (pages/) and App Router (app/) can coexist in the same Next.js project, so plan this as an incremental, route-by-route migration — not a big-bang rewrite done on one branch all at once.
</task>

<migration_plan_requirements>
- Order routes by risk and traffic: recommend migrating low-traffic, low-risk routes first to validate the approach, and the highest-traffic/most-critical routes last, once the pattern is proven.
- For each data-fetching method in use, state its App Router equivalent and the mental model shift, not just a mechanical swap:
  - getStaticProps becomes an async Server Component that fetches directly, with the equivalent caching behavior expressed via fetch's cache/revalidate options, not a special function.
  - getServerSideProps becomes an async Server Component with a fetch call that opts out of caching (cache: 'no-store'), or reads a dynamic API like cookies()/headers() that forces dynamic rendering.
  - getInitialProps: flag this one explicitly as needing the most rework, since it ran on both server and client and has no direct App Router equivalent.
- Move shared elements from _app.tsx/_document.tsx into app/layout.tsx (the root layout) once, not per-route — this should happen early, since both routers can share global styles/providers through careful setup, but duplicate providers during the transition is a common source of bugs.
- Convert pages/api routes to app/api/.../route.ts one at a time, in whatever order matches the page migration, not as a separate all-at-once phase.
- Call out any Pages Router-only APIs still in use (next/router's useRouter differs from next/navigation's, custom _error.tsx handling, etc.) that need a direct behavioral adjustment, not just a file move.
</migration_plan_requirements>

<output_format>
A phased table: Phase | Routes/files migrated | Data-fetching conversion needed | Risk notes. Then a short "do this first, regardless of phase" list for the _app.tsx/_document.tsx to root layout move.
</output_format>
Customize the highlighted detailsoptional — the prompt above already works

Why this works

The single fact that makes this migration tractable instead of terrifying is one most teams don't realize going in: pages/ and app/ coexist in the same Next.js project, and Next.js resolves routes across both, so migration can happen one route at a time on main instead of on a long-lived branch that has to land all at once. Mapping each data-fetching method to its App Router equivalent as a mental-model shift rather than a mechanical rename matters because getServerSideProps and a no-store fetch in a Server Component aren't quite the same thing — the latter is just one fetch call opting out of caching, while the whole component around it defaults to static unless something forces it dynamic, which is a different way of thinking about the page. Explicitly flagging getInitialProps as the hard case, and ordering the plan by risk rather than alphabetically, both come from the same practical bias: prove the pattern on something that doesn't matter much before touching the route that generates revenue.

What you get back

Phase 1: migrate pages/blog/[slug].tsx (getStaticProps to an async Server Component with a cached fetch) — low traffic, low risk, validates the pattern. Phase 2: move _app.tsx's ThemeProvider and Header/Footer into app/layout.tsx once, shared by both routers going forward. Phase 3: pages/dashboard.tsx (getServerSideProps to a Server Component using cookies() to force dynamic rendering, since it's behind auth). Phase 4 (last, highest risk): the legacy account page using getInitialProps — flagged for a rewrite, not a mechanical conversion, since it has no direct equivalent.

Verified against

Claude Code Sonnet 4.6 · 2026-07-19

Cursor 2.1 · 2026-07-23

Changelog

  • 2026-07-19 Initial version, tested against Claude Code on a mixed Pages/App Router Next.js 16 project.

Need this built into your business?

If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.

EXPLORE CUSTOM SOFTWARE
All Next.js prompts

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY