· By John Kavanagh

getStaticProps vs. getServerSideProps in Next.js

Abstract image used to represent getStaticProps vs. getServerSideProps in Next.js
Image by Pawel Czerwinski.

In Brief

In the Next.js Pages Router, getStaticProps prepares shared page data at build time or during revalidation, whilst getServerSideProps runs for every request and can use requestspecific context. Prefer static generation when the same result can be reused; choose serverside rendering when freshness, authentication or request data genuinely requires it. Neither API applies to the App Router.

Once Next.js made page rendering strategies more explicit, one of the next practical questions became:

Which datafetching function should this page use?

For many Pages Router applications, that decision comes down to two familiar names:

  • getStaticProps
  • getServerSideProps

They can look similar on the surface because both provide props to a page. But the timing of when they run changes the behaviour of the page quite significantly.


getStaticProps prepares reusable static output

getStaticProps normally runs during the build. Dynamic routes using getStaticPaths with fallback: true can also generate a missing page after a request. Next.js 9.4 introduced background revalidation as a beta feature, so the function is not necessarily limited to one buildtime call.

Here is a simple TypeScript/TSX page that uses the buildtime case:

import React from 'react';
import type { ReactElement } from 'react';
import type { GetStaticProps } from 'next';

type HomePageProps = {
  message: string;
};

export const getStaticProps: GetStaticProps<HomePageProps> = async () => {
  return {
    props: {
      message: 'Hello from build time',
    },
  };
};

const HomePage = ({ message }: HomePageProps): ReactElement => {
  return <h1>{message}</h1>;
};

export default HomePage;

This example prepares its message during the build. Ondemand generation and revalidation are additional policies to configure when the page needs them.


getServerSideProps runs on every request

If a page exports getServerSideProps, Next.js runs that function when the request arrives:

import React from 'react';
import type { ReactElement } from 'react';
import type { GetServerSideProps } from 'next';

type DashboardPageProps = {
  message: string;
};

export const getServerSideProps: GetServerSideProps<
  DashboardPageProps
> = async () => {
  return {
    props: {
      message: 'Hello from the server',
    },
  };
};

const DashboardPage = ({ message }: DashboardPageProps): ReactElement => {
  return <h1>{message}</h1>;
};

export default DashboardPage;

Now the data can reflect the current request more directly.


The Important Difference is Timing

That is the core of the whole choice.

This is not just a naming exercise, either. On the Nando’s UK & Ireland Replatform, those rendering choices had direct consequences for cacheability, editorial workflows, and how quickly different parts of the site could respond to change.

getStaticProps asks:

"Can this route share generated data across visitors, with an appropriate policy for generating or refreshing it?"

getServerSideProps asks:

"Does this page need requesttime work?"

Everything else follows from that distinction.


getStaticProps is ideal when the data is stable enough

Good fits often include:

  • marketing pages
  • blog posts
  • documentation
  • landing pages
  • content that changes infrequently

If the data does not need to be fetched freshly on every request, buildtime generation is usually a strong option because it reduces server work and often makes the page faster to serve.


getServerSideProps is better for requestspecific pages

This is a better fit when the content genuinely depends on the incoming request:

  • authenticated pages
  • account dashboards
  • requestspecific search results
  • personalised content
  • pages requiring fresh server data for every request

In these cases, buildtime generation would either be wrong or too limited.


The Functions May Look Similar, but Their Operational Cost is Not

This is easy to underestimate.

getStaticProps prepares shared output during the build, during ondemand generation, or when configured background revalidation runs. In Next.js 9.4, revalidation is still a beta feature using unstable_revalidate.

getServerSideProps does the work again and again as requests arrive.

That does not make serverside rendering bad. It simply means it should be reserved for pages that truly need it rather than used by default because it feels more dynamic.


getServerSideProps also receives request context

Because it runs at request time, it can access context tied to the incoming request, such as query parameters, params, headers, and cookies.

That is one of the reasons it suits personalised or protected pages more naturally.

getStaticProps does not receive the same requestspecific context, even when a request triggers generation. Its result is intended to be reused across visitors.


It Helps to Think in Terms of Page Contracts

Ask what promise the page makes to the user.

If the page promise is:

"Show me the latest requestspecific information for this visitor right now,"

then getServerSideProps may be the right tool.

If the page promise is:

"Show me the current published content for this route,"

then getStaticProps may be a better match.

That framing usually leads to better choices than just asking which API feels newer or more powerful.


A Content Page Example

Suppose we are building a guide page from a CMS.

A published guide read by many visitors is a good candidate for getStaticProps when its output can be shared. Decide whether a rebuild is enough to refresh it or whether the application needs the available generation and revalidation options.

This is one of the areas where Next.js feels especially strong.


A Dashboard Example

Now consider a signedin customer dashboard showing accountspecific orders.

That page depends on:

  • who the user is
  • what their current data is
  • details only known at request time

That makes getServerSideProps much more sensible. Trying to force it into buildtime generation would be working against the nature of the page.


Faster is Not the Only Question

Developers sometimes reduce the conversation to "static is faster" and leave it there.

That is incomplete.

Static generation often is faster to serve, but correctness matters more than raw speed. A page that is very quick and structurally wrong for the request is not a success.

The better question is whether the performance profile matches the data needs honestly.


This is Also About Infrastructure Shape

Choosing getServerSideProps means committing to requesttime execution. That has implications for:

  • how it behaves under load
  • caching
  • latency
  • deployment cost

Again, these tradeoffs may be entirely justified. The point is simply that they exist and should be deliberate.


Do Not Choose Server‑Side Rendering Out of Caution Alone

Many teams instinctively reach for requesttime rendering because it feels safer: "at least the data will always be fresh."

Sometimes that is true, but it can also lead to unnecessary work on every request for pages that could have been generated once up front with no meaningful downside.

Next.js is most effective when we use its flexibility to reduce waste, not when we default to the heaviest option.

If you want the broader renderingmodel version of this discussion, I broke that out separately in Static Generation vs. ServerSide Rendering in Next.js. This piece is really about the datafetching functions that sit on top of that choice.


Choose Based on When the Page Should Exist

Both functions return props, but they make different promises. getStaticProps generates reusable output, with buildtime, ondemand and beta revalidation options in this June 2020 context. getServerSideProps runs for each request and can use that request's data. Choose according to how the page may be shared and how fresh it needs to be.

Once that distinction is clear, the API names stop feeling confusing and start feeling descriptive.

Postscript

July 2020: Next.js 9.5 made Incremental Static Regeneration stable, replacing the beta unstable_revalidate option with revalidate. A time interval makes a page eligible for background regeneration on a later request; it does not guarantee that the content is never older than that interval. This builds on the beta behaviour available when the article was first published in June.

Planning a platform change?

I help teams make difficult platform work clearer, from architecture decisions and migrations to launch recovery, performance, and search visibility.