Server-Side Rendering (SSR)
Explore how server side rendering (SSR) works in Next.js, including its benefits like improved SEO and security, and its impact on performance and user experience. Understand when to use SSR and how to implement it using getServerSideProps for dynamic content.
We'll cover the following...
Even though server-side rendering (SSR) sounds like a new term in the developer’s vocabulary, it’s actually the most common way of serving web pages. If we think of languages such as PHP, Ruby, or Python, they all render the HTML on the server before sending it to the browser, which will make the markup dynamic once all the JavaScript content has been loaded.
Well, Next.js does the same thing by dynamically rendering an HTML page on the server for each request, then sending it to the web browser. The framework will also inject its scripts to make the server-side rendered pages dynamic in a process called
Imagine we’re building a blog and want to display all the articles written by a specific author on a single page. This can be a great use case for SSR: a user wants to access this page, so the server renders it and sends the resulting HTML to the client. At this point, the browser will download all the scripts requested by the page and hydrate the DOM, making it interactive without any kind of page refresh or glitch. From this point, thanks to React hydration, the web app can also become a single-page application (SPA), taking all the advantages of both client-side rendering (CSR) and SSR.
Advantages of SSR
Talking about the advantages of adopting a specific rendering strategy, SSR provides multiple benefits over the standard React CSR:
More secure web apps: Rendering a page on the server side means that activities such as managing cookies, calling private APIs, and data validation happen on the server, so we’ll never expose private data to the client.
More compatible websites: The website will be available even if the user has disabled JavaScript or uses an older browser.
Enhanced search engine optimization: Since the client will receive the HTML content as soon as the server renders and sends it, the search engine spiders (bots that crawl the web pages) will not need to wait for the page to be rendered on the client side. This will improve our web app’s SEO score.
Limitations of SSR
Despite those great advantages, there are times when SSR might not be the best solution for our website. In fact, with SSR, we will need to deploy our web application to a server that will rerender a page as soon as it’s required. As we’ll see later, with both CSR and static site generation (SSG), we can deploy static HTML files to any cloud provider, such as Vercel or Netlify, for free (or at a meager cost); if we’re already deploying our web app using a custom server, we have to remember that an SSR app will always lead to a more significant server workload and maintenance costs.
Another thing to remember when we want the server side to render our pages is that we’re adding some latency to each request; our pages might need to call some external API or data source, and they’ll call it for every page render. Navigating between server-side rendered pages will always be slower than navigating between client-side rendered or statically served pages.
Of course, Next.js provides some great features for improving navigation performances.
Another thing to consider is that by default, a Next.js page is statically generated at build time. If we want to make it more dynamic by calling an external API, a database, or other data sources, we’ll need to export a particular function from our page:
As we can see, the page only prints the This is the index page. text inside a div. It doesn’t need to call external APIs or any other data source to work, and its content will always be the same for each request. But now, let’s pretend that we want to greet the user on every request; we’ll need to call a getServerSideProps function:
Code explanation
In the preceding example, we used the Next.js reserved getServerSideProps function for making a REST API call on the server side for each request. Let’s break it down into small steps so that we can better understand what we’re doing:
Line 1: We start by exporting an
asyncfunction calledgetServerSideProps. During the build phase, Next.js will look for every page exporting this function and make them dynamically server-side rendered for each request. All the code written within this function scope will always be executed on the server side.Lines 2–8: Inside the
getServerSidePropsfunction, we return an object containing a property calledprops. This is required because Next.js will inject thosepropsinside our page component, making them available both on the client and server side. In case you’re wondering, we don’t need to polyfill the fetch API when we use it on the server side because Next.js already does that for us.Lines 10–12: We then refactor the
IndexPagefunction, which now accepts apropsparameter containing all thepropspassed from thegetServerSidePropsfunction.
When running this code, Next.js will always dynamically render our IndexPage on the server, calling an external API and showing different results as soon as we make changes in our data source.
Using browser APIs with SSR
As seen at the beginning of this section, SSR provides some significant advantages but has some caveats. If we want to use any component that relies on browser-specific APIs, we’ll need to render it on the browser explicitly because, by default, Next.js renders the entire page content on the server, which doesn’t expose certain APIs, such as window or document.