Articles

Next.js App Router vs Pages Router: What's the Difference

The App Router uses React Server Components and nested layouts; the Pages Router is Next.js's original file-based model. How they differ and when to pick each.

Takina Takina · · 4 min read
Code editor showing a component file structure

Next.js ships two different ways to structure a project: the App Router, built around React Server Components and nested layouts, and the Pages Router, the original file-based routing model the framework launched with. Both are still supported, but they lead to noticeably different code, so picking the right one up front saves a painful migration later.

How the two routers are structured

The Pages Router maps files in a pages/ directory directly to routes: pages/about.js becomes /about, and pages/posts/[id].js becomes /posts/:id. Data fetching happens through exported functions like getServerSideProps or getStaticProps, and every component in the tree is a client component by default — it ships JavaScript to the browser and can use hooks like useState freely.

The App Router uses an app/ directory where folders map to route segments and a page.js file inside a folder marks it as a routable page. Layouts are defined with layout.js files that wrap their child segments and persist across navigations without re-rendering. Components inside app/ are React Server Components by default — they render on the server, send no JavaScript to the client, and can await data directly inside the component body instead of exporting a separate data-fetching function. Reaching for useState, useEffect, or browser APIs requires an explicit "use client" directive at the top of the file. For a deeper look at what that default actually buys you, see what React Server Components are.

Comparison

Pages RouterApp Router
Directorypages/app/
Rendering defaultClient componentServer component
Data fetchinggetServerSideProps / getStaticPropsasync/await inside components
LayoutsManual, via _app.js and custom wrappersNative, via nested layout.js files
Loading and error statesManual conditional renderingConvention-based loading.js / error.js
StreamingLimitedBuilt in, via Suspense boundaries
MaturityStable since Next.js’s early releasesNewer, actively the primary investment

Why Server Components change the data-fetching story

In the Pages Router, a page component and its data-fetching function are two separate exports that Next.js stitches together at build or request time. In the App Router, a server component can just await fetch() (or a database call) directly in its body, and the result renders into HTML on the server — no client-side loading state needed for that initial render. This cuts down on the amount of client-side JavaScript and lets you compose data-fetching close to where it’s used, similar in spirit to how Astro’s islands architecture keeps most of a page static and only hydrates the interactive parts.

Streaming is the other big shift. Because server components can be rendered independently and wrapped in <Suspense>, a slow data source doesn’t have to block the whole page — the shell can ship immediately while individual sections stream in as their data resolves. If you’re new to Suspense boundaries in this context, React Suspense covers the mechanics in more depth.

Client components still matter

Not everything belongs on the server. Anything that needs interactivity — form state, click handlers, browser-only APIs, effects — still needs to be a client component, marked with "use client". The App Router’s model is to push client components as far down the tree as possible: a page can be mostly server-rendered, with a small interactive widget (a like button, a dropdown) as the only client component embedded in it. State libraries you’d reach for inside those client components, like Zustand or Redux, work the same way they always have — they just can’t run on the server.

Migration considerations

Next.js allows both routers to coexist in the same project during a migration — routes not yet moved to app/ keep working from pages/. That said, a few things trip people up:

  • Data libraries built around client-side fetching (some React Query patterns, for example) need adjustment since server components can fetch directly and don’t need a client-side cache for the initial load.
  • Context providers (theme, auth) generally need to live in a client component boundary, since React context isn’t available inside server components.
  • Third-party libraries that assume they’re always running in the browser (accessing window at module scope, for instance) will error inside a server component unless they’re wrapped in a client boundary.

When to choose which

For a new project, the App Router is the more capable option — smaller client bundles, native layouts and streaming, and the direction Next.js is actively building toward. The Pages Router remains a reasonable choice for a small, mostly-static site that doesn’t need any of that, or for teams with a large existing Pages Router codebase where a full rewrite isn’t worth the cost right now. There’s no requirement to migrate an already-working Pages Router app just to be on the newer model.

The takeaway

The Pages Router and App Router are two different rendering models bolted onto the same framework: file-to-route mapping and client-first rendering versus nested layouts, server components by default, and built-in streaming. New projects should start with the App Router; existing Pages Router apps can keep running as-is or migrate incrementally, since Next.js supports both directories side by side.

Takina Takina · · 5 min read

React Server Components, Explained Without the Hype

React Server Components render exclusively on the server and stream a serialized result — no client JS shipped for that component. Here's what that actually means.

#React #Web Development #JavaScript
Takina Takina · · 4 min read

React Compiler: Automatic Memoization Explained

The React Compiler automatically memoizes components and values at build time, cutting most manual useMemo, useCallback, and React.memo calls.

#React #JavaScript #Web Development