Two routers,
one framework
Next.js ships two complete routing systems. The original pages/ router made React server-rendering easy and ruled from 2016. The newer app/ router, stable since 2023 and the default since v13, rebuilt the foundation on React Server Components — moving the default execution environment from the browser to the server. This is a tour of both architectures: how each one turns a request into a page, what problem each was built to solve, and the specific forces that made Next.js change its mind. Click any node, card, or highlighted term to dig in.
One request, two lifecycles.
The same HTTP request enters the top. On the left, the Pages Router renders an entire React tree on the server and then ships all of it to the browser to hydrate. On the right, the App Router renders Server Components to a serialized payload that ships no JavaScript, streams the result, and hydrates only the interactive islands. Click any node to open its deep-dive.
The same task, four eras.
"Fetch the posts, render the list." Watch how Next.js answered that one request over time — and how the client-side JavaScript cost collapses as the work moves onto the server. Step through from the earliest pattern to today's async Server Component.
Eleven axes of difference.
Each card is one dimension where the two routers diverge. Click for the deep cut: how the Pages Router did it, how the App Router does it, why the change, and what it costs you. Several cards include a small interactive diagram, and every highlighted term is clickable.
Five forces, one rewrite.
The App Router wasn't a coat of paint on the old one — it's a different architecture because the old one had hit structural ceilings. These are the forces that pushed the default execution environment from the browser back to the server.
React itself moved
React shipped as a first-class primitive. A framework built around the old "everything is a client component" model couldn't expose them cleanly. The App Router is the runtime that makes RSC real.
Layouts that persist
The Pages Router had no real ; the hack re-ran on every navigation. The App Router makes a true tree that survives navigation — .
Streaming & Suspense
Page-level data fetching is all-or-nothing: nothing renders until resolves. The App Router is built on React 18 , so a static shell ships instantly and slow data fills in via .
Kill the waterfall
Tying data to the page meant child components fetched on the client, one after another — a . With server-side , each component fetches its own data on the server, in parallel.
Less JavaScript shipped
In the Pages Router the whole tree hydrates whether it's interactive or not. Server Components ship zero JS, so a content-heavy page can hand the browser almost nothing — the single biggest lever on .
The cheat sheet.
The same eleven dimensions, side by side, for when you just need the one-liner.
pages/, one file per routeapp/, folders with special filesgetServerSideProps / getStaticPropsasync components + fetch_app + getLayout patternlayout.tsxloading.tsx + streaming Suspense'use server')_error.tsx, app-wideerror.tsx boundary per segmentIt is not a clean kill.
The App Router is the future and the default, but "default" is not "always." The new model trades simplicity for power: the server/client boundary and the caching layers are real cognitive cost. Here is the honest split.
Default for anything new
- You want minimal client JS on content-heavy pages — marketing, docs, commerce, dashboards with a static shell.
- You need or per-section and .
- You want data and secrets to stay on the server via and .
- You're starting fresh and want the features Next.js ships to first.
Stable, simple, known
- You have a large, working app where a rewrite buys little — it's in , not removed.
- Your app is fundamentally a client-side SPA and the server-first model adds friction, not value.
- You depend on libraries or patterns that haven't fully adapted to the RSC boundary.
- The team already moves fast in it and the 's learning curve isn't worth paying right now.
app/ and pages/ coexist, so teams routinely migrate rather than all at once. New surfaces go in app/; the old ones keep working until they're worth moving.