DEV Community

Cover image for A detailed guide on how to implement Server-side Rendering (SSR) in a NextJs Application
The ERIN
The ERIN

Posted on • Updated on

A detailed guide on how to implement Server-side Rendering (SSR) in a NextJs Application

Introduction

Server-side Rendering (SSR) is becoming increasingly important in web development due to its ability to improve website performance and user experience. Unlike Client-side Rendering (CSR), where the website's content is generated on the user's device, server-side rendering generates the HTML on the server and sends it to the client. This method can improve website load time, search engine optimization, and accessibility.

Next.Js is a popular framework for building React applications, and it offers built-in support for server-side rendering. With Next.js, we can easily set up our application to generate HTML on the server and deliver it to the client, providing a seamless user experience and optimized website performance. In this detailed guide, we will build a cryptocurrency web app to show how to implement SSR in a Next.js application. We will also cover the basic concepts behind server-side rendering and walk through the steps required to set up SSR in our Next.js application. By the end of this article, you will have a solid understanding of improving your website's performance and SEO by implementing SSR in your Next.js application.

 

Pre-rendering: A built-in Feature in Next.js

Regarding page rendering with Next.js, pre-rendering is a fundamental component. It is a key feature of Next.js, which means that static HTML content is generated in advance rather than dynamically on each request.
When comparing the page source of a traditional React.js web app and a Next.js web app, it is clear that the Javascript code is loaded before the contents are rendered to the user, which is a bad user experience. However, when inspecting the contents of a Next.js page source, the HTML is already generated with all the necessary data, making Next.js the most efficient method for improved web performance and user experience.

Next.js gives us the option of selecting one of two pre-rendering modes:

  1. SSG (Static Side Generation): This is Next.js's default pre-rendering mode, in which HTML pages are generated at build time and served to the user as static files. This approach is appropriate for websites with static content because it reduces server load and provides the fastest possible performance.

  2. Server-side rendering (SSR): SSR, on the other hand, generates HTML pages on the server whenever a user requests them. This approach is useful for websites with frequently changing content or that require dynamic data because it can provide a more responsive user experience while ensuring the content is always up to date.

Understanding the Server-Side Rendering Process

Server-side rendering is fast becoming a popular technique widely used in web development that involves rendering a web page on the server before sending it to the client, unlike client-side rendering, where the page is rendered in the browser first after the server has sent the necessary HTML, CSS, and JavaScript bundled files.

To fully understand the server-side rendering process, it is important to know the key players involved. It includes the server and the client.

The server is responsible for handling all incoming requests made from the client side and sending the appropriate response. In the context of SSR, this involves rendering the requested web page on the server and sending the resulting HTML, CSS, and JavaScript to the client.

The client is the web browser through which a user accesses the web application. In SSR, the client gets the rendered HTML, CSS, and JavaScript from the server and displays the contents on the web page.

Now that we've identified the two major players in server-side rendering, let's look at the actual thought process behind it.
The client requests the server for a specific web page as the first step in the server-side rendering process.

The server will receive the request and determine which page the client is looking for. The server will then render the requested page on the server, which includes generating the page's HTML, CSS, and JavaScript and compiling them into a complete web page.

After rendering the web page on the server, the server will send the resulting HTML, CSS, and JavaScript to the client. The client will then use these files to show the user the web page.

 

Implementing SSR with Data Fetching in Next.js

Data fetching is an essential part of developing any web application. Next.Js provides several methods for retrieving data, including server-side rendering, static site generation, client-side rendering, incremental static regeneration, and dynamic routing. However, for this article, we will only look at server-side generation. You can learn about the other types by reading the Next.js documentation.

 

getServerSideProps: a built-in Function for Data Fetching in Next.Js

Next.js includes a built-in function called getServerSideProps that allows us to fetch data from the server with each request. To use server-side rendering on a page, we must export getServerSideProps, and the server will call this function on every request.

getServerSideProps Syntax

export default function Page( {data} ){
   return <>YOU CAN DISPLAY YOUR DATA ACCORDINGLY</>
}
export async function getServerSideProps() {
   // Your code
   const data = .... ;

   // Passing data to the page using props
   return {
       props : {data}
   }
}
Enter fullscreen mode Exit fullscreen mode

In place of data we can use a different variable name. We can also pass multiple props by using commas "," to separate them.

 

Key Notes about getServerSideProps

  1. getServerSideProps only runs on the server and never on the client.

  2. It runs at the request time, and the web page is pre-rendered with the returned props specified inside.

  3. getServerSideProps can only be exported from a page. You cannot export it from non-page files. It will not work if you make getServerSideProps a page component property.

  4. getServerSideProps should only render a page whose data must be fetched at the requested time. If the data does not need to be rendered during the request, consider fetching it on the client side or using static side generation.

  5. The getServerSideProps function must return an object containing the data that will be passed to the page component as props. If the function does not have a return statement, it cannot pass data to the page component.

 

Fetching data using getServerSideProps

 

Step 1: Setting up a Next.Js Application
Now that we understand the server-side rendering process, we can go ahead and make requests to the server and fetch data from it.

Next.Js includes server-side rendering support; with this framework, we can easily make server requests and pre-render our web content without writing complex coding functions or methods.

To get started, we have to set up a development environment where we can start building our web app. If you have ever built a React app, you are familiar with [create-react-app](https://create-react-app.dev/), which sets up the development environment. Next.Js has its command called create-next-app.
Run the following command via a terminal. I am using npm as my package manager, but you can use your preferred package manager's commands instead:

npx create-next-app crypto-web-app

Enter fullscreen mode Exit fullscreen mode

This command will create a new Next.js project and all other app dependencies in your folder directory.

Once all of the dependencies have been installed, navigate to the crypto-web-app directory by running

cd crypto-web-app

Enter fullscreen mode Exit fullscreen mode

To start the development server run:

npm run dev or yarn dev

Enter fullscreen mode Exit fullscreen mode

To view the application, go to http://localhost:3000.

 

Step2: Getting a third-party API endpoint
Let us go to our application's pages/index.js file. In this file, we will get the top nine cryptocurrency coins by market value from CoinGecko, an external API. Let us look through coingecko's API documentation to find our endpoint. The endpoint we require is in the coins category. We only need to set a basic configuration, and when we click the Execute button, it should provide us with an endpoint.

CoinGecko API End point:

 <https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=9&page=1&sparkline=false>

Enter fullscreen mode Exit fullscreen mode

 

Step 3: Declaring the getServerSideProps function. Add the following code to our index.js file. We will go through the code step by step:

import React from "react";
import styles from "/styles/Home.module.css";
import { FiArrowDown, FiArrowUpRight } from "react-icons/fi";

function Home({ data }) {
  return (
    // Renders the data passed as props from the getServerSideProps
    <div className={styles.container}>
      <h1>Cryptocurrencies by Market Cap</h1>

      <div className={styles.crypto__container}>
        {data.map((crypto) => (
          <div key={crypto.id} className={styles.crypto__child}>
            <img src={crypto.image} alt={crypto.symbol} />
            <h3>{crypto.name}</h3>

            <div className={styles.crypto__price}>
              <p>$ {crypto.current_price.toLocaleString()}</p>
              {crypto.price_change_percentage_24h < 0 ? (
                <span className={styles.arrow__down}>
                  <FiArrowDown className={styles.price__icon} size={20} />
                  {crypto.price_change_percentage_24h.toFixed(2)}%
                </span>
              ) : (
                <span className={styles.arrow__up}>
                  <FiArrowUpRight className={styles.price__icon} size={20} />
                  {crypto.price_change_percentage_24h.toFixed(2)}%
                </span>
              )}
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

// This function gets triggered on every request
export async function getServerSideProps() {
  // This fetches the data from the Coingecko external API
  const response = await fetch(
    "<https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd&order=market_cap_desc&per_page=9&page=1&sparkline=false>"
  );
  const data = await response.json();

  // Pass data to the page component via props
  return {
    props: {
      data,
    },
  };
}

export default Home;

Enter fullscreen mode Exit fullscreen mode

We declared the async getServerSideProps function and used JavaScript's built-in fetch API function to retrieve data from the CoinGecko API endpoint. Remember that we must declare a return statement in order to pass the data obtained from the API to our page component.

We accepted the props passed by the getServerSideProps method in our Home function component. We used the JavaScript map() method to display a list of cryptocurrencies sorted by market value as a child element of the component.

Here is the CSS to add more styling to the web app:

@import url('<https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600;700&display=swap>');

.container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 100vw;
  height: 100%;
  padding: 100px 0;
  font-family: 'Nunito Sans', sans-serif;
}

.container h1 {
  margin-bottom: 40px;
}

.crypto__container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  grid-column-gap: 25px;
  grid-row-gap: 80px;
}

.crypto__child {
  box-shadow: rgba(0, 0, 0, 0.16) 0px 10px 36px 0px, rgba(0, 0, 0, 0.06) 0px 0px 0px 1px;
  padding: 30px 15px;
  border-radius: 7px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.crypto__child img {
  width: 50%;
  margin-bottom: 7px;
}

.crypto__child h3 {
  font-size: 20px;
  margin: 7px 0;
}

.crypto__price {
  display: flex;
  align-items: center;
  gap: 10px;
}

.arrow__down {
  color: red;
  display: flex;
  align-items: center;
}

.arrow__up {
  color: green;
  display: flex;
  align-items: center;
}

/* Mobile */
@media (max-width: 700px) {
  .container {
    padding: 70px 0;
    font-family: 'Nunito Sans', sans-serif;
  }

  .container h1 {
    margin-bottom: 30px;
    font-size: 25px;
  }

  .crypto__container {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: repeat(9, 1fr);
    grid-column-gap: 0;
    grid-row-gap: 20px;
  }

  .crypto__child {
    padding: 25px 13px;
  }

  .crypto__child img {
    width: 50%;
  }

  .crypto__child h3 {
    font-size: 17px;
  }
}

/* Tablet and Smaller Desktop */
@media (min-width: 701px) and (max-width: 1120px) {
  .container {
    padding: 80px 0;
  }

  .container h1 {
    margin-bottom: 30px;
  }

  .crypto__container {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(5, 1fr);
    grid-column-gap: 25px;
    grid-row-gap: 80px;
  }

  .crypto__child img {
    width: 70%;
  }

  .crypto__child h3 {
    font-size: 19px;
  }

  .crypto__price {
    display: flex;
    align-items: center;
    gap: 10px;
  }
}
Enter fullscreen mode Exit fullscreen mode

If we go to http://localhost:3000 in our browser, we should see a list of nine cryptocurrencies fetched on each request to the server before being returned to us in the browser.

 

Conclusion

Server-Side Rendering (SSR) is a modern method in modern web development that offers numerous advantages, including improved performance and SEO, faster interaction time, better accessibility, a better user experience, and easier maintenance. The page loads faster because the initial view is rendered on the server, which improves the user experience. Furthermore, search engine bots can easily crawl and index content, helping to improve search engine rankings. SSR enables faster loading times, reducing the time it takes for a page to become interactive for the user. The browser does not need to wait for JavaScript to load and execute because the initial view is rendered on the server, which can significantly reduce TTL. SSR can also help to improve accessibility by ensuring that all users have access to the page's content.

Furthermore, using SSR in a Next.js application can help reduce the complexity of managing client-side states and rendering.

Finally, implementing Server-Side Rendering (SSR) into a Next.js application can yield significant benefits. However, it is critical to understand that implementing SSR can add complexity to the application; as a result, it is critical to carefully consider the use cases and opt for other types of pre-rendering modes that Next.js provides. Nonetheless, implementing SSR in a Next.js application with the right approach can help to provide a more robust, faster, and smoother web experience for users, leading to higher engagement and better outcomes for web applications.

Resources

If you liked my article and found it useful, please leave a tip. Your contribution would enable me to continue producing high-quality articles for you.

Image description

Thank you for your continued support, and I look forward to providing you with more useful content in the future.

Top comments (0)