Next.js App Router vs Pages Router

Next.js ships with two routing systems. The Pages Router arrived with the earliest versions of the framework. The App Router joined later and now serves as the recommended choice for new projects. Knowing both systems helps you read older tutorials, maintain existing applications, and pick the right foundation for a fresh build.

The Everyday View

Picture two floor plans for the same house. The first plan gives every room a single door and one fixed layout. The second plan lets rooms share hallways, lights, and walls with their neighbors. Both plans produce a livable house. The second plan gives you more control over the parts that rooms have in common.

The Pages Router follows the first plan. The App Router follows the second.

Folder Layout Side by Side

Each router reads a different top-level folder. The diagram below shows the same website built with both systems.

Pages Router                      App Router
-----------------------------     -----------------------------
pages/                            app/
  _app.js        (wrapper)          layout.js      (wrapper)
  index.js       -> /               page.js        -> /
  about.js       -> /about          about/
  blog/                               page.js      -> /about
    [slug].js    -> /blog/hello     blog/
  api/                                [slug]/
    hello.js     -> /api/hello          page.js    -> /blog/hello
                                    api/
                                      hello/
                                        route.js   -> /api/hello

The Pages Router turns every file into a route. The App Router turns every folder into a route and looks for special files inside it, such as page.js, layout.js, and route.js.

Key Differences

FeaturePages RouterApp Router
Route sourceFiles in pages/Folders in app/
Default component typeClient-hydrated React componentsServer Components
Shared layout_app.js and _document.jsNested layout.js files
Data loadinggetStaticProps, getServerSidePropsAsync components with fetch
API endpointspages/apiRoute Handlers in route.js
Loading and error screensManual codeloading.js and error.js
StreamingLimitedBuilt in

Data Fetching Compared

Data loading shows the biggest day-to-day difference. The Pages Router asks you to export a special function. The App Router lets the component fetch its own data.

Pages Router Version

export async function getServerSideProps() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();
  return { props: { posts } };
}

export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((p) => <li key={p.id}>{p.title}</li>)}
    </ul>
  );
}

App Router Version

export default async function Blog() {
  const res = await fetch('https://api.example.com/posts');
  const posts = await res.json();
  return (
    <ul>
      {posts.map((p) => <li key={p.id}>{p.title}</li>)}
    </ul>
  );
}

The second version has fewer moving parts. The data call sits right beside the markup that uses it, so a reader follows one path from top to bottom.

Navigation Hooks Differ

Both routers offer a useRouter hook, but the import paths differ. The Pages Router imports from next/router. The App Router imports from next/navigation. Mixing the two paths causes confusing errors, so check the import line whenever a tutorial code sample fails.

Using Both Routers Together

A single project can hold both folders. This setup supports gradual migration. You move one page at a time from pages/ into app/ while the rest of the site keeps working.

One rule applies: two files cannot claim the same URL. If pages/about.js and app/about/page.js both exist, the build stops with an error. Delete the old file once the new version is ready.

Which One to Choose

Choose the App Router When

  • You start a new project.
  • You want nested layouts that persist between page changes.
  • You want Server Components to reduce the JavaScript sent to the browser.
  • You plan to use Server Actions, streaming, or Suspense.

Stay With the Pages Router When

  • An existing production site already runs on it without problems.
  • Your team depends on libraries that do not yet support Server Components.
  • The cost of migration outweighs the benefit for your project.

Migration Tips

Move Small Pages First

Start with simple pages such as an About page or a Contact page. These pages carry little data logic and teach you the new folder rules with low risk.

Replace Data Functions Gradually

Convert getStaticProps into an async component with a cached fetch. Convert getServerSideProps into an async component with an uncached fetch. Test each page in the browser before you remove the old file.

Move Shared Layout Last

Rebuild the content of _app.js and _document.js inside app/layout.js after most pages have moved. The root layout must include the html and body tags.

Quick Summary

The Pages Router offers a simple, file-based model with years of community examples. The App Router offers a folder-based model with layouts, Server Components, and streaming. New projects benefit most from the App Router, and existing projects can adopt it one page at a time.