- Next.js
- Pages Router & Migration Strategy
- Pages Router Data Fetching: getServerSideProps vs getStaticProps
Pages Router Data Fetching: getServerSideProps vs getStaticProps
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
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';34interface ProductPageProps {5 product: { id: string; name: string; price: number };6}78export default function ProductPage({ product }: ProductPageProps) {9 return (10 <div>11 <h1>{product.name}</h1>12 <p>${product.price}</p>13 </div>14 );15}1617// 1. Define pre-generated paths at build time18export const getStaticPaths: GetStaticPaths = async () => {19 return {20 paths: [{ params: { id: '1' } }, { params: { id: '2' } }],21 fallback: 'blocking', // SSR on first request if path is ungenerated22 };23};2425// 2. Fetch data at build time + background ISR revalidation26export const getStaticProps: GetStaticProps<ProductPageProps> = async (context) => {27 const { id } = context.params!;28 const product = await fetchProduct(id as string);2930 return {31 props: { product },32 revalidate: 60, // ISR: Revalidate in background every 60 seconds33 };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
Can you use getStaticProps inside the app directory?
No. The `app` directory replaces these functions with native async Server Components, `generateStaticParams`, and `"use cache"`.
How do you migrate getStaticProps to App Router?
Turn the page into an async Server Component and call the data function directly inside the component body.
