Fetching and hydrating a Next.JS app using `getServerSideProps` and `getStaticProps`

Learn how and when to use `getStaticProps`, `getServerSideProps` and `getInitialProps` in a Next.JS project

Pablo A. Del Valle H.
The Startup
10 min readMay 19, 2020

--

How to properly use `getStaticProps`, `getServerSideProps` and `getInitialProps`
Photo by KOBU Agency on Unsplash

When your app needs to process data from an external source (as in a fetch for a remote JSON file) you have two options.

  1. Retrieve the payload on the client-side, at run time (such as implementing `getServerSideProps`) or,
  2. Produce the data at build time, so that the visitor gets the bundled version of the page you want to serve (for this you can try `getStaticProps`).

You may be inclined to try `getInitialProps`, and it would probably do the job just fine, the big catch is that `getInitialProps` will disable `Automatic Static Optimization`.

Also, you need to consider the side-effects of your decision making, for instance: what kind of processing this data is going to get? Is it going to be complex computations? Is this data needed as a dependency for another action or perhaps to reach another end-point? Is your data across a CORS (Cross-Origin Resource Sharing) wall? How often your data source changes? What are your SEO requirements? And not least, privacy and security.

Automatic Static Optimization

When you run `next build` command, Next.JS will optimize each page generated to 3 types of emits:

  1. λ (Lambda): these pages will render at run time, they can either implement `getInitialProps` or `getServerSideProps`.
  2. ○ (Static): pages rendered as Static will only contain HTML, these pages are super fast.
  3. ● (SSG): Static-Site-Generated pages will also be served as static emits. These differ from Static pages in that they will render HTML and pre-fetched props (from `getStaticProps` static method).

Seeing it in action

First off, this is not a thorough stress analysis. For that, you need to create thousands of tests that can generate statistically significant results plus, using different sizes of payloads to evaluate the performance of such cases. The data obtained here only represents the results I got for my particular case.

So, let’s see how much, performance-wise, we can gain by having Static pages.

Consider the following example page:

The previous code will render a simple list of users, similar to this:

Simple list of users rendered as a static build.
A simple list of users rendered as a static build.

For this example, there are no props, no state, and the JSX returned is always the same, meaning there are no dependencies when generating this HTML.

Components that return the same result when given the same props and states are called pure components, such as this one.

Functional components that are exported using the `React.memo` “high-order” component function behaves the same way as a pure component.

These components are highly optimized and very fast.

Now, let’s run `next build` to generate a production build. Let’s analyze the output:

Notice the `/users` row: 382 bytes in size and the first load weights 59.1 kilobytes. Also, see the empty circle icon to the left of the`/users` row ( ). This means this page is a Static build. All this is pretty good!

However, it’s highly unlikely your website will keep all data hardcoded into the HTML like this. It would mean every update has to be done manually and can potentially result in unintended mistakes.

Another way to generate this table is by using a constant variable that will extract the list of users, like so:

Notice the variable is set outside the component. This will result in the following output after running `next build`:

This still keeps our `/users` build to be Static but will increase the size of this render to 422 bytes (from 382 bytes in our previous example).

If we try and put the const variable inside the component, like this:

This will generate the following output from `next build`:

The bundle is still Static, and the size of the file is practically the same (2 more bytes). No significant difference found here.

Using the state to store the data

Another approach you may try is to use the local state of the component. Let’s try that:

This extremely simple sample generates the following output:

We still see the static file being output and the file size a few bytes larger (21 bytes, almost insignificant) than the previous test.

Calling an external data source

All these tests are all well and good, however, they are not very realistic. Let’s try and call an external data source using `Axios`:

This one is doing something that you may actually find in the “real world”. We also present a “loading” message while we fetch data from an external data source, in this case from JSON Placeholder. This service serves several sets of “fake” JSON files for you to play with for free.

How did the bundle behave in this case?

We see several interesting things here. Now our `/users` page grew from a few hundreds of bytes to 6.14 kilobytes. This might seem inconsequential, however, bear in mind that this is almost FIFTEEN TIMES larger than the previous bundle.

Our users' page still is Static. Evidently, importing extra libraries, and a few more lines of code made the file grow larger. Yet, there is another thing to consider, when we browse this page in our local server, we see that the data is loaded asynchronously after rendering:

Notice the XHR request in the console of Chrome. Now, this is a fairly tiny request. If you think to scale, however, for a regular size site all these requests will add up and it is your responsibility to consider all these factors when you deploy a website.

`getServerSideProps`, “almost-hybrid” solution for data fetching

We can pass the data as a prop to the page component. For this, Next.JS provides the special method `getServerSideProps`.

Consider the following code:

The `next build` output is a little different this time:

The `/users` page is now 429 bytes… a very small bundle… That’s pretty good! However, there is another important difference. The page is now a Server file (check the lambda symbol λ to the left of the page name).

Now, I call this example an `almost hybrid`. The reason for this is, if you go directly and open this page in a browser, you’ll see there is no loading of the external data in the console log. This is due to the fact that the data is fetched in the server. However, if we navigate to this page from a different location, say… using the <Link /> component from Next.JS library, you will get the data fetched on the client-side.

There is one more way we can load the external data.

Bundling at the server-side using `getStaticProps`

There are several reasons why you may want to serve your page fully rendered from the server. You may need this page to be readily available for site engine optimization, or maybe the page requires special data transformation that might be expensive at the client-side, to protect private APIs that you don’t want to expose to your visitors.

The best way to do this in Next.JS is with `getStaticProps`. Consider the following code:

Observe the output from `next build`:

At this point, you’ll notice the full circle next to the `/users` row. This means that this bundle is sending a Static file from the server.

This page will be built on the server and will not trigger an XHR request from the client. This is quite a great thing since we have a small size bundle (faster download), it can be cached, SEO accessible, there are no additional requests for the visitors.

Of course, you may not always want to serve fully static pages. Financial services, user interactions (chats, emails, notifications), pages that get updated often (like blogs, news sites). So it’s important to consider every approach on a case by case basis.

So what is `getInitialProps` used for?

`getStaticProps` and `getServerSideProp` will be mainly used to fetch data from external sources, while `getInitialProps` can focus on preparing props to be populated before the page gets rendered.

Caveats

If used properly, these methods can be very powerful but, at the same time, they can be very harmful to the performance of your app when not taken with care.

One thing to consider is that, since these methods are executed before the page gets rendered, they do not have access to the Window, the Document objects, and, of course, any of the elements of the DOM.

When you manipulate the props before the rendering of the page you automatically disable Next.JS static pages optimization.

Thanks for reading!

Find me on LinkedIn, Medium, GitHub.

--

--