The Pages Router is the original Next.js routing system, built around the pages/ directory. Even though the App Router is now recommended, huge numbers of production codebases still run on the Pages Router, so this lesson covers its conventions.
What Is the Pages Router?
In the Pages Router, every file inside the pages/ directory automatically becomes a route based on its file path — pages/about.tsx becomes /about, and pages/index.tsx becomes /. Unlike the App Router, components in pages/ are Client Components in spirit: they render on request (or at build time) but are not React Server Components, and data fetching happens through special exported functions rather than async components.
Because the Pages Router predates React Server Components, its data-fetching model (getStaticProps, getServerSideProps, getStaticPaths) is function-based: you export a function alongside your page component, and Next.js calls it before rendering, passing the result in as props.
// pages/posts/[id].tsx
export async function getServerSideProps({ params }: { params: { id: string } }) {
const post = await fetch(`https://api.example.com/posts/${params.id}`).then((r) => r.json());
return { props: { post } };
}
export default function PostPage({ post }: { post: any }) {
return <h1>{post.title}</h1>;
}
getServerSideProps runs on every request on the server, and its return value is passed straight into the page component as props.
Pages Router File Conventions
pages/
_app.tsx // Wraps every page (like a root layout)
_document.tsx // Customizes the <html> document shell
index.tsx // Route: /
about.tsx // Route: /about
posts/
[id].tsx // Route: /posts/:id
api/
hello.ts // API route: /api/hello
_app.tsx wraps every page, similar to the App Router's root layout.tsx.
_document.tsx controls the top-level HTML document, including <html> and <head> structure.
Bracketed filenames like [id].tsx define dynamic route segments.
Files under pages/api/ automatically become serverless API endpoints.
Pages Router Cheat Sheet
The data-fetching functions and files that define Pages Router behavior.
API / File
Purpose
getStaticProps
Fetch data at build time (SSG)
getStaticPaths
Declare which dynamic routes to pre-render
getServerSideProps
Fetch data on every request (SSR)
_app.tsx
Global wrapper for every page
_document.tsx
Customize the HTML document shell
pages/api/*.ts
Serverless API routes
useRouter()
Access routing info from next/router
The Three Data-Fetching Functions
Pages Router pages choose their rendering strategy by exporting one specific function. Exporting nothing means the page is statically rendered at build time with no data; exporting getStaticProps fetches data at build time; exporting getServerSideProps fetches data on every request.
Function
When It Runs
Rendering Result
(none)
Build time only
Fully static HTML
getStaticProps
Build time (or on revalidation)
Static HTML with data (SSG/ISR)
getServerSideProps
Every request
Fresh HTML per request (SSR)
Can pages/ and app/ Coexist?
Yes — Next.js allows pages/ and app/ to exist in the same project simultaneously, which is exactly how most teams migrate incrementally: new routes are added under app/, while existing pages/ routes keep working unchanged until they're eventually ported over.
If the same route exists in both directories, the App Router takes priority, so plan migrations route-by-route rather than duplicating a path in both places.
Common Mistakes
Trying to use App Router-only APIs like Server Actions or "use client" inside pages/.
Forgetting that getStaticPaths is required whenever a dynamic route ([id].tsx) uses getStaticProps.
Assuming getServerSideProps and getStaticProps can both be exported from the same page — only one is allowed.
Duplicating the same route path in both pages/ and app/, causing unexpected routing conflicts.
Key Takeaways
The Pages Router uses the pages/ directory, where file paths map directly to routes.
Data fetching uses exported functions: getStaticProps, getStaticPaths, and getServerSideProps.
_app.tsx and _document.tsx play roles similar to the App Router's root layout.
pages/api/*.ts files become serverless API endpoints, similar to Route Handlers.
pages/ and app/ can coexist during an incremental migration to the App Router.
Pro Tip
If you're maintaining an older Next.js codebase, don't feel pressured to rewrite everything to the App Router at once — Next.js explicitly supports incremental migration, so move high-traffic or actively-developed routes first and leave stable pages on the Pages Router until there's a real reason to touch them.
You now understand both routing systems. Next, look closely at file-based routing conventions shared across both routers.