Next.js currently ships two entirely different routing systems side by side: the App Router (the app/ directory, the current default and the one this whole reference focuses on) and the older Pages Router (the pages/ directory, the only router Next.js had for years). Knowing both matters less for writing new code than for reading it — a huge amount of Next.js code in production, in tutorials, and in interview take-homes still predates the App Router entirely.
The App Router exists because the Pages Router hit a real architectural ceiling. Every page in the Pages Router is, at bottom, a component that renders once and ships its JavaScript to the browser — there's no built-in notion of "this part of the tree never needs to run in the browser at all." Data fetching lived in special exported functions (getServerSideProps, getStaticProps) attached to the page as a whole, which meant a deeply nested component that needed its own data had no way to fetch it independently — everything funneled up through the top-level page function first. And a slow page was slow all at once: the whole page waited on the whole data-fetching function before the browser saw anything.
The App Router rebuilds routing around three ideas the Pages Router structurally couldn't express:
None of that makes the Pages Router obsolete or wrong to use. You'll still run into it, and honestly still choose it, in a few real situations:
getServerSideProps returning a plain props object is a flatter, more predictable mental model than "some components run on the server, some in the browser, and the boundary between them is a directive you place yourself." For a small app with modest data needs, that simplicity is a legitimate trade-off, not a compromise.| Pages Router | App Router | |
|---|---|---|
| Directory | pages/ | app/ |
| Data fetching | getServerSideProps / getStaticProps, one per page | fetch (or any async call) directly inside any Server Component |
| Server-only code | Not a first-class concept | Server Components, by default |
| Layouts | Manual, via a custom _app.js wrapping every page | Nested layout.tsx files, scoped per route segment |
| Streaming | Not supported natively | Built in, via Suspense boundaries |
| Where you'll meet it | Existing apps, older tutorials | New projects, this reference |