How to Deploy Next.js13 app with SSG and SSR to AWS Amplify
Published: 2023-03-06 15:50:16

{% embed https://www.youtube.com/watch?v=5045cvJit04&ab_channel=ChristianNwamba %}

[Next.js](https://nextjs.org/) is a React-based framework for building server-side rendered (SSR) and static site-generated (SSG) applications.

Server-side rendering (SSR) means that the initial HTML for a page is generated on the server and sent to the client, which can improve the initial page load time and allow search engines to crawl and index the page more easily.

Static site generation (SSG) means that the HTML for a page is generated at build time rather than on the server or client side, which can improve the site's performance and reduce the load on the server.

Next.js allows developers to choose between these two rendering strategies based on the specific needs of their application.

In this article, you will learn how to build a Next.js application with SSG and SSR features and deploy the app with AWS Amplify.

## Prerequisites

The following are required to follow along in this post.

- Basic knowledge of React.js
- Node.js is installed on your computer to run some npm packages.
- AWS Amplify account; [sign up here](https://portal.aws.amazon.com/billing/signup#/start/email).

## Setting up the Next.js application

To bootstrap a new Next.js application, let's run the following commands in our terminal:

```
npx create-next-app <project-name>
```

After creating the application, navigate into the project directory and start the application with the following commands: open it with your default code editor.

```
cd <project-name> # to navigate into the project directory
npm run dev # to run the dev server
```

## Adding Tailwind to the Mix

Run the following commands to add tailwind, postcss and the auto prefixer and initialize tailwind and add the `tailwind.config` file in your project.

```
npm install -D tailwindcss postcss autoprefixer
npx tailwind init -p
```

Next, open the `tailwindcss.config.js` file at the root of our project and configure it like in the below to process every javascript and typescript file in our pages and components folder.

```js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
};
```

Next, open the `globals.css` file from the styles folder and import the tailwind CSS files like the below:

```cs
//globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

## Installing Date FNS

Install `date-fns` with the below command to show the difference between the SSG and SSR pages by showing the date and time the page was last served.

    npm install date-fns

## Building a Server Rendered Page

Here, use the `getServerSideProps()` function to fetch data from an external API at the request time in the `index.js` file like below:

```js
//pages/index.js
export async function getServerSideProps() {
  // Fetch data from external API
  const res = await fetch("https://fakestoreapi.com/users");
  const data = await res.json();
  // Pass data to the page via props
  return { props: { data, timeOfLoad: new Date().toISOString() } };
}
```

In the snippets above, we fetched data from the fakestore API endpoint, converted the data to `JSON` and returned it to the `return()` function so that the component function could access it.

Next, let’s create the component function and render the data from fakestore in it like in the below:

```js
//pages/index.js
import { formatRelative } from "date-fns";
import React from "react";

const Home = ({ data, timeOfLoad }) => {
  const relativeTimeOfLoad = formatRelative(Date.parse(timeOfLoad), new Date());
  return (
    <div className="mx-auto  w-3/4 my-16">
      <div className="my-8">
        <h2 className="text-6xl text-center">
          Contacts from Server Side Rendering{" "}
        </h2>
        <p className="text-center">{relativeTimeOfLoad}</p>
      </div>
      <div className="grid grid-cols-2 gap-4 md:grid-cols-3">
        {data.map((dt) => (
          <div
            key={dt.id}
            className="border-2 shadow-sm border-gray-200 rounded px-6 py-4 space-y-2"
          >
            <h3 className="text-2xl text-gray-800 capitalize">
              {" "}
              {dt.name.firstname} {dt.name.lastname}
            </h3>
            <p className="my-4 text-lg text-gray-800"> {dt.email}</p>
            <p className="my-4 text-md text-gray-800"> {dt.phone}</p>
            <p className="my-4 text-sm text-gray-500 uppercase">
              {" "}
              {dt.address.city}
            </p>
          </div>
        ))}
      </div>
    </div>
  );
};
export default Home;
```

In the snippets above, we:

- Imported `formatRelative` from the `date-fns` package installed earlier, grab `timeOfLoad` we passed from the `getServerSideProps` function and created a relative time between when the page was generated from the server and now.
- Rendered a title containing the page title, looped through the `data` we passed in the `getServerSideProps` function, and displayed the user details.

Now, run npm run dev in the terminal and head over to the browser to preview the rendered user cards.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678044084136_WhatsApp+Image+2023-01-10+at+11.01.52+AM+1.jpeg)

Next, let's create the SSG page to go along with the server-side rendered page we've created.
Create an `ssg.js` file inside the pages folder with the following snippets:

```js
export async function getStaticProps() {
  // Run API calls in parallel
  const productsResponse = await fetch("https://fakestoreapi.com/products");
  const products = await productsResponse.json();
  return {
    props: {
      product: products,
      timeOfLoad: new Date().toISOString(),
    },
  };
}
```

Here, we fetched our products using the `getStaticProps()` function, converted it to JSON and returned it as props.
We also attached a `timeOfLoad` prop just like we did in the SSR page.

Next, create an SSG function component which'll receive the product prop like in the below:

```js
//pages/ssg.js
import Link from "next/link";
import { formatRelative } from "date-fns";
const SSG = ({ product, timeOfLoad }) => {
  const relativeTimeOfLoad = formatRelative(Date.parse(timeOfLoad), new Date());
  return (
    <div className="mx-auto  w-3/4 my-16">
      <div className="my-8">
        <h2 className="text-6xl text-center">
          Products with Static Generation{" "}
        </h2>
        <p className="text-center">{relativeTimeOfLoad}</p>
      </div>
      {product.map((pr) => (
        <div
          className="border-2 shadow-sm border-gray-200 rounded p-3 my-4"
          key={pr.id}
        >
          <div className="space-y-2">
            <p className="font-bold"> Title: {pr.title}</p>
            <p> Description: {pr.description}</p>
            <p className="text-lg"> ${pr.price}</p>
          </div>
        </div>
      ))}
    </div>
  );
};
export default SSG;
```

Here we rendered the head, looped through the product prop and rendered the list of products; showing each product's details.
We imported `formatRelative` and repeated the process just like in the SSR page to show the relative time between when the page was sent from the server and now.

In the browser, we would confirm that the products were rendered.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678037335129_s_C348D939E6A4675C774669788E74848D253B658E5A5202CCDD1897F0CBCF7A6B_1669800093905_Screenshot2022-11-30at10.21.23+1.png)

## Deploy to Amplify Hosting

Deploying our app with AWS Amplify allows us to test the time difference between the SSR and the SSG pages.

First, push the codes to GitHub or other preferred git providers, [Login](https://signin.aws.amazon.com/signin?redirect_uri=https%3A%2F%2Fconsole.aws.amazon.com%2Fconsole%2Fhome%3FhashArgs%3D%2523%26isauthcode%3Dtrue%26state%3DhashArgsFromTB_us-east-2_e9f471da6e3be96e&client_id=arn%3Aaws%3Asignin%3A%3A%3Aconsole%2Fcanvas&forceMobileApp=0&code_challenge=gFswi9FBOrQ8L8VOKwtbKxESRHErajQN6tHg7_aHppo&code_challenge_method=SHA-256) to the AWS console, search for Amplify and select it from the list of services.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678046273093_Screenshot+2023-03-05+at+20.50.58.png)

Next, click on the New app drop-down and select Host Web App. Select GitHub or your Git provider on the next page and click the continue button.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678022314391_preferredGit+1.png)

Next, click on the Connect branch button, select the repository you intend to host, select the main branch and click on the Next button to proceed.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678044238471_addRepoBranch+1.png)

On the next page, configure the build settings and click on the Next button.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678044300514_buildsettings+1.png)

Review your settings on the next screen and click the Save and deploy button to start the deployment processes. After deploying, click on the live link provided by Amplify to access your app.

![](https://paper-attachments.dropboxusercontent.com/s_5A2239BC3371671C8784225E365D363E83F67DBD170250F6F2316134AE4A94A8_1678047573526_Screenshot+2023-03-05+at+21.07.51.png)

While testing the live app, notice that the SSR page always matches the current time because the `getServerSideProps` function is always called when the page is refreshed.
Whereas `getStaticProps` on the SSG page is called only when the page is loaded.

## Conclusion

This post discussed how to build a Next.js application that includes a serverside rendered page and a statically generated page and deploy the application using AWS Amplify.