Next.js Curriculum
MediumPages Router Migration100% Free25 min read

Pages Router Data Fetching: getServerSideProps vs getStaticProps

The 30-Second Interview Answer

In Pages Router, data fetching was defined per-page via exported functions: getServerSideProps executed on every request on the server (SSR), while getStaticProps executed at build time to produce static HTML/JSON (SSG), with optional revalidate for ISR. Unlike App Router, data fetching could not be colocated inside child components.

Learning Objectives

Compare getServerSideProps and getStaticProps execution lifecycles.

Explain the data serialization boundary between getStaticProps and page components.

Implement Incremental Static Regeneration (ISR) using the revalidate property.

Identify the architectural limitations of page-level data fetching that led to App Router.

Prerequisites & Background Knowledge
Pages Router file system conventionsSSR and SSG conceptsJSON serialization

Why Interviewers Care

Essential for interviews at companies maintaining large legacy Next.js codebases transitioning to App Router.

The Challenge

Contrast getServerSideProps and getStaticProps in the Pages Router. Explain why data fetching was restricted to top-level page files, and how ISR revalidation worked under the hood.

Code Architecture & Implementation

1// pages/products/[id].tsx (Pages Router convention)
2import { GetStaticProps, GetStaticPaths } from 'next';
3
4interface ProductPageProps {
5 product: { id: string; name: string; price: number };
6}
7
8export default function ProductPage({ product }: ProductPageProps) {
9 return (
10 <div>
11 <h1>{product.name}</h1>
12 <p>${product.price}</p>
13 </div>
14 );
15}
16
17// 1. Define pre-generated paths at build time
18export const getStaticPaths: GetStaticPaths = async () => {
19 return {
20 paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
21 fallback: 'blocking', // SSR on first request if path is ungenerated
22 };
23};
24
25// 2. Fetch data at build time + background ISR revalidation
26export const getStaticProps: GetStaticProps<ProductPageProps> = async (context) => {
27 const { id } = context.params!;
28 const product = await fetchProduct(id as string);
29
30 return {
31 props: { product },
32 revalidate: 60, // ISR: Revalidate in background every 60 seconds
33 };
34};

Architectural Explanation

In Pages Router, data fetching operated strictly at the route level. This caused severe prop drilling: a root page had to fetch data for every widget on the screen and pass it down through 10 component layers. Furthermore, if a page used getServerSideProps, the entire page became dynamic, preventing partial static caching. React Server Components in App Router solved this by allowing any component in the tree to fetch its own data asynchronously.

Common Mistakes & Anti-Patterns

Attempting to export both `getStaticProps` and `getServerSideProps` from the same file, which throws a Next.js error.

Returning Date objects in `props` without converting to ISO strings, causing JSON serialization errors.

Calling internal API routes via fetch() inside `getServerSideProps`, adding loopback latency.

Interview Follow-Up Traps

The interviewer asks: "Can getStaticProps access the incoming HTTP request cookies?" No! `getStaticProps` runs at build time or in background ISR; it has no access to client request headers or cookies.

Frequently Asked Questions

What is fallback: "blocking" versus fallback: true?

`fallback: "blocking"` serves SSR HTML on the first request for an ungenerated page. `fallback: true` immediately serves a fallback shell while generating the page in the background.

No. The `app` directory replaces these functions with native async Server Components, `generateStaticParams`, and `"use cache"`.

Turn the page into an async Server Component and call the data function directly inside the component body.