SyntaxStudy
Sign Up
Next.js Pages Router: getStaticProps and getServerSideProps
Next.js Beginner 1 min read

Pages Router: getStaticProps and getServerSideProps

The Pages Router (the original Next.js routing system using the pages/ directory) remains fully supported and uses a different data-fetching model based on exported async functions. getStaticProps runs at build time and returns props that are baked into a static HTML file. It is ideal for content that does not change frequently, such as blog posts, documentation, or marketing pages. getServerSideProps runs on every request and is used when you need fresh data on each page load, such as a user dashboard or search results page. It receives a context object containing req, res, params, and query, giving you full access to the incoming HTTP request. The function must return an object with a props key, a redirect key, or a notFound: true key. getStaticPaths works alongside getStaticProps for dynamic routes. It tells Next.js which parameter values to pre-render at build time. The fallback option controls behaviour for paths not returned by getStaticPaths: false returns a 404, true shows a fallback state while the page is generated on demand and cached, and 'blocking' generates the page on the first request and waits before responding. These concepts are largely replaced by generateStaticParams in the App Router.
Example
// pages/blog/[slug].tsx  (Pages Router)

import type {
  GetStaticPaths,
  GetStaticProps,
  InferGetStaticPropsType,
} from 'next';

interface Post {
  slug: string;
  title: string;
  content: string;
}

// Runs at build time - pre-renders a static HTML file per post
export const getStaticProps: GetStaticProps<{ post: Post }> = async (ctx) => {
  const slug = ctx.params?.slug as string;
  const res = await fetch(`https://api.example.com/posts/${slug}`);

  if (!res.ok) return { notFound: true };

  const post: Post = await res.json();

  return {
    props: { post },
    revalidate: 60, // ISR: regenerate at most once per minute
  };
};

// Tell Next.js which slugs to pre-render
export const getStaticPaths: GetStaticPaths = async () => {
  const res = await fetch('https://api.example.com/posts');
  const posts: Post[] = await res.json();

  return {
    paths: posts.map((p) => ({ params: { slug: p.slug } })),
    fallback: 'blocking', // generate unknown slugs on demand
  };
};

export default function BlogPost({
  post,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return (
    <article>
      <h1>{post.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: post.content }} />
    </article>
  );
}