Skip to main content

Pages Router vs App Router

Answer

Next.js has two routing systems: the original Pages Router (pages directory) and the newer App Router (app directory) introduced in Next.js 13.

Router Comparison

File Structure

# Pages Router
pages/
├── index.js → /
├── about.js → /about
├── blog/
│ ├── index.js → /blog
│ └── [slug].js → /blog/:slug
├── _app.js → Root wrapper
└── _document.js → HTML document

# App Router
app/
├── page.js → /
├── layout.js → Root layout
├── about/
│ └── page.js → /about
├── blog/
│ ├── page.js → /blog
│ └── [slug]/
│ └── page.js → /blog/:slug
└── loading.js → Loading UI

Data Fetching

// PAGES ROUTER - getServerSideProps (SSR)
export async function getServerSideProps(context) {
const data = await fetchData();
return { props: { data } };
}

export default function Page({ data }) {
return <div>{data.title}</div>;
}

// PAGES ROUTER - getStaticProps (SSG)
export async function getStaticProps() {
const data = await fetchData();
return {
props: { data },
revalidate: 60, // ISR
};
}
// APP ROUTER - Direct async in component
async function Page() {
const data = await fetchData(); // Server Component
return <div>{data.title}</div>;
}

// With caching
async function Page() {
const data = await fetch("/api/data", {
cache: "force-cache", // SSG
// or: next: { revalidate: 60 } // ISR
// or: cache: 'no-store' // SSR
});
}

Layout System

// PAGES ROUTER - _app.js
export default function App({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}

// Per-page layouts with getLayout
Page.getLayout = function (page) {
return <DashboardLayout>{page}</DashboardLayout>;
};
// APP ROUTER - layout.js (nested layouts)
// app/layout.js - Root layout
export default function RootLayout({ children }) {
return (
<html>
<body>
<Header />
{children}
<Footer />
</body>
</html>
);
}

// app/dashboard/layout.js - Dashboard layout
export default function DashboardLayout({ children }) {
return (
<div className="dashboard">
<Sidebar />
<main>{children}</main>
</div>
);
}

Special Files (App Router)

FilePurpose
page.jsRoute UI
layout.jsShared wrapper
loading.jsLoading UI (Suspense)
error.jsError UI
not-found.js404 UI
route.jsAPI endpoint

Key Differences

FeaturePages RouterApp Router
Default componentsClientServer
Data fetchinggetServerSideProps, getStaticPropsasync components, fetch
LayoutsManual with getLayoutNative with layout.js
Loading statesManualloading.js (Suspense)
Error handling_error.jserror.js (per route)
StreamingNoYes
React 18 featuresLimitedFull support

Migration Path

// Start with App Router for new projects
// Migrate gradually - both can coexist

// pages/old-page.js - Still works
// app/new-page/page.js - New routes

// Shared components work in both
// app/components/Button.js

Key Points

  • App Router is the recommended default for new projects
  • Server Components are default in App Router
  • App Router uses folders for routes, Pages uses files
  • Layouts in App Router are truly nested and persistent
  • Both routers can coexist during migration
  • App Router enables streaming and React 18 features