Architecture deep-dive · Next.js 16 · App Router vs Pages Router

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.

2
Routers, one app
'23
App Router stable
0 KB
JS from a Server Component
11
Axes compared
01 — Two mental models

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.

Request → response · left vs right
Pages Router App Router Render Data / hydrate Cost
INPUT HTTP request → /blog/hello Pages Router · since 2016 pages/blog/[slug].tsx STEP 01 · ROUTE Match the page file one file = one route, flat STEP 02 · DATA (SERVER) Run get*Props for the page page-level only · props flow down STEP 03 · RENDER Render the whole tree → HTML one mode per page: SSR or SSG STEP 04 · SHIP + HYDRATE Ship the entire tree as JS full-tree hydration Interactive page heavy First Load JS App Router · default since v13 app/blog/[slug]/page.tsx STEP 01 · ROUTE Match nested segments layout wraps page, composable STEP 02 · RENDER (SERVER) Render Server Components fetch in-component · 0 KB JS STEP 03 · STREAM Stream HTML + RSC payload shell first, Suspense holes fill STEP 04 · HYDRATE Hydrate 'use client' islands only the interactive parts Interactive page minimal First Load JS
02 — How data fetching evolved

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.


      
03 — Head to head

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.

04 — Why Next.js switched

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.

Force 01

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.

Force 02

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 — .

Force 03

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 .

Force 04

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.

Force 05

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 .

05 — At a glance

The cheat sheet.

The same eleven dimensions, side by side, for when you just need the one-liner.

Dimension
Pages Router
App Router
Directory
pages/, one file per route
app/, folders with special files
Default component
Client Component (ships + hydrates)
Server Component (0 KB JS)
Data fetching
getServerSideProps / getStaticProps
async components + fetch
Shared UI
_app + getLayout pattern
Nested, persistent layout.tsx
Loading states
Manual, per-page
loading.tsx + streaming Suspense
Mutations
API routes + client fetch
Server Actions ('use server')
Rendering choice
Per page (SSR or SSG)
Per component; PPR blends both
Errors
_error.tsx, app-wide
error.tsx boundary per segment
Caching
Mostly explicit / simple
Layered cache; defaults changed in v15
Status (2026)
Supported, maintenance mode
Default, recommended for new apps
Mental model
Client-first, server bolted on
Server-first, client opt-in
06 — Which should you use?

It 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.

Reach for App Router

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.
Pages Router still fits

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.
You don't have to choose globally. Both routers run in the same app — 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.
Back to JIT-Atlas