Next.js SSG vs SSR Part 1: Static Page

Next.js SSG vs SSR Part 1: Static Page

Welcome to the Next.js SSG vs SSR article series! Here we try out and compare the two rendering modes of the Next.js framework: static site generation and server-side rendering. This is the first article of the series, where we are going to get known with the Next.js rendering modes and test them on a static page of a Next.js demo application. Basic familiarity with Next.js and React should be enough to get started.

Introduction

Next.js is a React framework for creating multi-page web applications with efficient rendering to clients. It offers two basic optimization methods:

  • static site generation (SSG) - bundling static HTML pages with inline client scripts that can be directly hosted;
  • server-side rendering (SSR) - compiling a requested page with its contents on a server with further hydration by client scripts.

Each of these methods has its own features and use cases. We'll be talking about them in detail throughout the article.

The Sandbox App

Imagine you've got a business website. It has a static super-optimized home page for SEO purposes. There can also be a blog page which needs to fetch list of articles from some backend, or an article page, which in addition needs to parse the URL parameters, and so on. Now you are questioning how to make each page of your website to perform better.

This is what our target app will be like, I've created a Next.js demo app for our experiments. If you would also like to try out what we will be doing in the article, please clone the app repository from GitHub:

$ git clone https://github.com/toxa16/nextjs-ssg-vs-ssr-demo.git

and checkout to the app version suited for this article:

$ git checkout c12e4f0f081894ed2fe6847bb8af41e95a6c8bdb

Today we will focus on the simplest part of the app: the static homepage.

But before any experiments start, we need to figure out how to actually tell Next.js whether it should generate our website statically or render it server-side.

Enter getInitialProps

A primary structure unit of a Next.js app is a page. Pages are React components with special role in a Next.js app. Every page represents a URL route within the app. All page components files are located under pages/ directory (by default), thus the app defines its routes based on the page filenames and filepaths, rendering for a route corresponding page component contents.

Next.js allows to set rendering method by pages. By default static site generation is applied. To switch a particular page to server-side rendering mode we need to define getInitialProps method for the page component.

getInitialProps is a function that is run on server before the page is rendered. As its name claims, the function initializes properties of the page component. The getInitialProps can be defined for a page as a property for function component:

function MyPage() {
  // page component contents
}

MyPage.getInitialProps = () => {
  // ...
}

export default MyPage;

or as a static method for class component:

export default class MyPage extends React.Component {
  static getInitialProps() {
    // ...	
  }

  // page component contents
}

Now, after we have explored what the getInitialProps is, let's take a look at how Next.js pages perform with and without getInitialProps.

SSG vs SSR: The Homepage

In this article we will test out the homepage of our target app to see how the SSG and SSR affect its performance. The page doesn't contain any dynamic client elements and doesn't request any data from server. Here is how our homepage looks like:

Homepage Intro

That's it, just some static introductory text.

The homepage component is localed in pages/index.js file. Let's take a look at its code:

// ...

function Homepage() {
  // homepage static content
}

/*Homepage.getInitialProps = () => {
  return {};
}*/

export default Homepage;

We can see a minimal getInitialProps method applied to the Homepage component. Since getInitialProps is required to return an object by its API, it will return an empty object for simplicity.

Homepage SSG

Currently the getInitialProps method is commented out, which means that static site generation mode is now set for the homepage.

This is where our experiments start. We are going to test out the homepage rendering performance. Of course, we won't do that in Next.js development mode, but make a production build:

$ cd /path/to/nextjs-ssg-vs-ssr-demo
$ npx next build # or "npm run build"

The build command console output confirms that our homepage has been statically generated:

Homepage SSG Build Console Output

Now we will start the Next.js production server to host the build on our local machine:

$ npx next start # or "npm start"

If we now visit localhost:3000 in a web browser, we will be able to see the homepage load time in the developer tools panel:

Homepage SSG Load Time

Since these load time values are quite unstable, we can't really rely on single measurement. Therefore, I have reloaded the homepage 10 times on my local machine, recorded the load time values and calculated averages. Here are my results:

Homepage SSG Metrics Chart

Average values of 10 measurements (homepage - SSG mode):

  • DOMContentLoad - 43.2 ms;
  • Load - 214 ms;
  • Finish - 121.6 ms.

That is how our statically generated homepage performs (on my local machine).

Homepage SSR

Now let's try out the homepage in server-side rendering mode. To enable SSR we have to uncomment the homepage getInitialProps:

// ...

Homepage.getInitialProps = () => {
  return {};
}

export default Homepage;

To apply code changes we rebuild our app:

$ npx next build # or "npm run build"

The homepage is now built in SSR mode:

Homepage SSG Build Console Output

And start the production server:

$ npx next start # or "npm start"

Let's now visit localhost:3000 in a web browser. Apparently, the homepage looks identically as it does in SSG mode (that's what we expected though):

Homepage SSR Look & Load

After reloading the homepage 10 times in my web browser I've measured the following load time data:

Homepage SSG Metrics Chart

Average measurement values (homepage - SSR mode):

  • DOMContentLoad - 55.4 ms;
  • Load - 218.6 ms;
  • Finish - 123.9 ms.

If we compare the results from both experiments, we'll see that they are pretty similar. Although the SSR average values are slightly higher, all differences are within statistical boundaries.

Thus, we can make a conclusion that for a static page without server requests the Next.js static site generation and server-side rendering (empty getInitialProps) modes performance is practically identical.

Conclusion

You have read the first article of the Next.js SSG vs SSR series, where we have explored the two rendering methods of the Next.js framework: static site generation and server-side rendering. We have briefly discussed what these rendering methods are and tried out how each of them performs on a static page of a Next.js application.

In the next article of the series we will test the SSG and SSR methods on a page that fetches data from backend server. Don't forget to leave your thoughts, wishes and complains in comments on Twitter :) Thanks for reading!

Photo by @glenncarstenspeters from Unsplash