Skip to content

Migration playbook: Next.js Pages Router → Next.js App Router

Next.js Pages Router to App Router migration

Move a Pages Router application to the App Router and React Server Components route by route, shipping less client-side JavaScript without a rewrite.

Migration drivers

Why teams make this move

Driver 01

Large client bundles

Every page's components and dependencies downloaded and hydrated in the browser, even when they only render static content.

Driver 02

Data-fetching waterfalls

getServerSideProps plus client-side useEffect fetches that delay content and cause layout shifts.

Driver 03

Server data in client state

Global client stores holding data that belongs on the server.

Execution sequence

How the migration runs

Each phase ends with a check you can verify — data parity, error rates, latency — and the rollback path is agreed before any traffic moves.

  1. 01Phase

    Run both routers side by side

    The pages/ and app/ directories work together, so routes can move one at a time.

  2. 02Phase

    Root layout and design system

    Porting _app.tsx and _document.tsx into app/layout.tsx and moving head tags to the Metadata API.

  3. 03Phase

    Route-by-route conversion

    Moving high-traffic content routes first and pushing 'use client' down to the interactive leaves.

  4. 04Phase

    Server Actions and cache tags

    Replacing hand-written API routes for mutations with Server Actions and revalidateTag.

Risk prevention

Pitfalls that derail this migration

Risk 01

'use client' too high in the tree

Marking a high-level component as a client component, which pulls its whole subtree into the client bundle.

Risk 02

Dynamic APIs in shared layouts

Reading cookies() or headers() in a shared layout, which opts every route below it out of static rendering.

Risk 03

Misunderstood caching

Not knowing which fetches and routes are cached, which leads to stale content or redundant requests.

Before and after

What we measure

We take a baseline before any change and report the same numbers after cutover, from your own tools. They are the evidence of whether the migration worked — not figures promised in advance.

JS per route
Client JavaScript, gzip, from the build output — before and after
LCP and INP
Field data at p75 (CrUX or your RUM), before and after
Indexed URLs
Search Console coverage and redirects, checked after each release

Questions

Frequently asked migration questions

Yes. Next.js serves the pages/ and app/ directories together, so you can move one route at a time and keep releasing. Just don't define the same route in both directories.

Server Components render on the server and send HTML without their JavaScript, so there is less to download and hydrate. That usually helps LCP and INP; we measure field data before and after to confirm it on your pages.

Rehearse the cutover before the real one

Tell us about your data volume, traffic and timeline. An engineer will reply within one business day to set up a call about the migration plan and its rollback path.