How to Deploy Next.js13 app with SSG and SSR to AWS Amplify

Christian Nwamba - Mar 6 '23 - - Dev Community

Next.js 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.

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>


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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


Enter fullscreen mode Exit fullscreen mode

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.



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


Enter fullscreen mode Exit fullscreen mode

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



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


Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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:



//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() } };
}


Enter fullscreen mode Exit fullscreen mode

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:



//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;


Enter fullscreen mode Exit fullscreen mode

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.

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:



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(),
    },
  };
}


Enter fullscreen mode Exit fullscreen mode

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:



//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;


Enter fullscreen mode Exit fullscreen mode

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.

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 to the AWS console, search for Amplify and select it from the list of services.

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.

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.

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

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.

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.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .