---
title: "05 — App Router vs Pages Router — Two Generations of Next.js Routing"
uid: app-vs-pages-router
tags: ["roadmap:nextjs", "pages-router", "server-components", "routing", "app-router", "nextjs"]
excerpt: "Two coexisting routers: the App Router is the modern Server-Components-native successor, the Pages Router is the original, still supported — but new features land on App."
date: 2026-08-13T03:28:02+0000
source: https://www.aveshina.my.id/en/blog/app-vs-pages-router
---

Two routers in one framework is a real source of confusion for anyone arriving fresh, so I mapped the split. The model that clicked: **Next.js has two coexisting routers — the Pages Router (the original) and the App Router (the modern, Server-Components-native successor).** Both are file-system based, both are supported, but the App Router is where new features land and where the framework's direction points [1][3].

The reason this distinction exists at all is historical. Before Next.js 13, there was only the Pages Router. The App Router arrived as a fundamentally different architecture built on React Server Components, and rather than break every existing project, Next.js kept both. New projects default to App; existing projects migrate incrementally.

## Pages Router — the original

The Pages Router is built around the pages/ directory. Every file in pages/ becomes a route based on its filename — pages/about.js becomes /about, pages/blog/[slug].js becomes /blog/:slug [2]. It's simple and battle-tested, and its data-fetching model uses special functions like getServerSideProps and getStaticProps that run only on the server.

```
// pages/about.tsx — Pages Router
export default function About() {
  return <h1>About</h1>;
}

export async function getServerSideProps() {
  // runs on the server, passes props to the page
  return { props: { data: await fetchData() } };
}
```

The Pages Router's limits are what motivated the App Router: no native Server Components, data fetching tied to special functions rather than the component tree itself, and layouts bolted on rather than first-class.

## App Router — the modern default

The App Router lives in the app/ directory and is built on React's latest features — Server Components, Suspense, and Server Functions [3]. The key shifts from Pages Router:

- **Server Components by default.** Every component in app/ is a Server Component unless I explicitly mark it 'use client'. Data fetching is just async/await inside the component — no special functions.
- **Layouts are first-class.** A layout.tsx wraps all pages beneath it and persists across navigation, so shared UI like nav bars doesn't remount.
- **Nested routing with colocated concerns.** Special files (page.tsx, layout.tsx, loading.tsx, error.tsx, template.tsx) each handle one concern per route segment.
- **Streaming built in.** Suspense boundaries let the server stream HTML as it becomes ready.

```
// app/about/page.tsx — App Router
export default async function About() {
  const data = await fetchData(); // just async/await
  return <h1>{data.title}</h1>;
}
```

```figure
<svg viewBox="0 0 720 300" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="Pages Router versus App Router. Left column: pages/ directory with files like about.js, blog/[slug].js; data via getServerSideProps; no nested layouts. Right column: app/ directory with layout.tsx, page.tsx, loading.tsx, error.tsx; Server Components by default; async/await data fetching; nested layouts persist.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">

    <!-- Pages Router -->
    <rect x="30" y="30" width="320" height="240" rx="10" fill="#fee2e2" stroke="#dc2626" stroke-width="1.5"/>
    <text x="190" y="52" font-size="13" font-weight="700" fill="#7f1d1d" text-anchor="middle">Pages Router (pages/)</text>
    <g font-family="ui-monospace, monospace" font-size="11" fill="#7f1d1d">
      <text x="50" y="80">pages/</text>
      <text x="70" y="100">index.js    → /</text>
      <text x="70" y="120">about.js    → /about</text>
      <text x="70" y="140">blog/[slug].js → /blog/:slug</text>
    </g>
    <text x="50" y="172" font-size="10" fill="#7f1d1d">• data: getServerSideProps</text>
    <text x="50" y="190" font-size="10" fill="#7f1d1d">• layouts: bolted on</text>
    <text x="50" y="208" font-size="10" fill="#7f1d1d">• components: client by default</text>
    <text x="50" y="226" font-size="10" fill="#7f1d1d">• no Server Components</text>
    <text x="50" y="252" font-size="10" font-style="italic" fill="#7f1d1d">original, battle-tested</text>

    <!-- App Router -->
    <rect x="370" y="30" width="320" height="240" rx="10" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="530" y="52" font-size="13" font-weight="700" fill="#052e16" text-anchor="middle">App Router (app/)</text>
    <g font-family="ui-monospace, monospace" font-size="11" fill="#052e16">
      <text x="390" y="80">app/</text>
      <text x="410" y="100">layout.tsx   (wraps all)</text>
      <text x="410" y="120">page.tsx     → /</text>
      <text x="410" y="140">blog/[slug]/page.tsx</text>
      <text x="410" y="160">loading.tsx  (suspense)</text>
      <text x="410" y="180">error.tsx    (boundary)</text>
    </g>
    <text x="390" y="208" font-size="10" fill="#052e16">• data: async/await inline</text>
    <text x="390" y="226" font-size="10" fill="#052e16">• Server Components by default</text>
    <text x="390" y="244" font-size="10" fill="#052e16">• nested layouts persist</text>
    <text x="390" y="262" font-size="10" font-style="italic" fill="#052e16">modern, RSC-native</text>
  </g>
</svg>
```

## Which to use

The official recommendation is unambiguous: for new projects, use the App Router, and for existing Pages Router projects, migrate [1][4]. The App Router is where React's latest features — Server Components, Suspense, Server Actions — actually work. The Pages Router remains supported and even improved, but it's the maintenance path, not the leading edge.

That said, the migration isn't free. The two routers can coexist in one project (an app/ and a pages/ directory side by side), which lets teams migrate route-by-route rather than all at once. The coexistence is intentional — Next.js made it possible to adopt incrementally.

## How I use this

Every new project I start uses the App Router exclusively. For any Pages Router code I touch in existing projects, I treat it as legacy-but-stable and migrate opportunistically when the surrounding work justifies it. The decision is rarely about which is "better" in isolation — it's about whether I'm starting fresh (App, always) or working inside an existing commitment (respect the existing router, migrate when sensible).

## References

[1] Vercel, "Next.js Docs — App Router and Pages Router," 2024. [Online]. Available: [https://nextjs.org/docs#app-router-and-pages-router](https://nextjs.org/docs#app-router-and-pages-router)

[2] Vercel, "Pages Router," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/docs/pages](https://nextjs.org/docs/pages)

[3] Vercel, "App Router tutorial," Next.js Docs, 2024. [Online]. Available: [https://nextjs.org/learn/dashboard-app](https://nextjs.org/learn/dashboard-app)

[4] DCS Ink, "Next.js: App Router vs Pages Router," dev.to, 2024. [Online]. Available: [https://dev.to/dcs-ink/nextjs-app-router-vs-pages-router-3p57](https://dev.to/dcs-ink/nextjs-app-router-vs-pages-router-3p57)

[5] "Next.js App vs. Pages Router — Which one is better?," YouTube, 2024. [Video]. Available: [https://www.youtube.com/watch?v=EYDOXzpTRvw](https://www.youtube.com/watch?v=EYDOXzpTRvw)

```quiz
Q: Which directory does the App Router use?
- pages/
- app/
correct: 1
explain: The App Router lives in the app/ directory. The Pages Router uses pages/. Both can coexist in one project for incremental migration.

Q: In the App Router, components are Server Components by default. How do you opt into client-side behavior?
- Wrap the component in <ClientBoundary>
- Add the 'use client' directive at the top of the file
correct: 1
explain: Every component in app/ is a Server Component unless explicitly marked with the 'use client' directive, which opts that file (and its imports) into the client bundle.

Q: What's a key data-fetching difference between Pages Router and App Router?
- Pages Router uses async/await; App Router uses getServerSideProps
- Pages Router uses special functions (getServerSideProps); App Router uses plain async/await inside the component
correct: 1
explain: The Pages Router couples data fetching to functions like getServerSideProps/getStaticProps. The App Router lets Server Components fetch data with plain async/await directly in the component body.

Q: The official Next.js recommendation for new projects is…
- Pages Router, because it's more stable
- App Router, because it's where new features and React's latest capabilities land
correct: 1
explain: The App Router is the modern, Server-Components-native router and the recommended choice for new projects. The Pages Router remains supported but is the maintenance path.
```
