Front-End Web & Mobile

5 Next.js features that are better with AWS Amplify

Next.js is a popular React framework that enables server-side rendering and static site generation for React apps. When combined with AWS Amplify, a set of purpose-built tools and features that enables frontend web and mobile developers to quickly and easily build full-stack applications on AWS, developers can build some really powerful apps.

Here are 5 Next.js features that are enhanced by AWS Amplify:

1. Data Fetching & APIs

Next.js offers 4 primary ways of fetching data: Static Generation (SSG), Server-side Rendering (SSR), Client-side (CSR) and Incremental Static Generation (ISG).

For dynamic data, AWS Amplify provides an integrated way to provision and connect to a data source, such as Amazon DynamoDB through AWS AppSync along with AWS Amplify Libraries to query and mutate the data.

As an illustration, you can define a schema for a Todo application that includes queries, mutations, and subscriptions. The queries allow you to fetch Todos from the API. The mutations allow you to create, update, and delete Todos. The subscriptions allow your app to receive real-time updates when Todos are added, updated, or deleted by other users. Under the hood, AWS Amplify uses AWS AppSync, which is a managed GraphQL server. AWS AppSync handles resolving the GraphQL operations by connecting to different data sources, such as a NoSQL database like Amazon DynamoDB. For subscriptions, AWS AppSync uses WebSocket connections to push data from the server to subscribed clients in real time. So your Todo app can stay up to date with the latest Todos without having to poll the API for changes.

Prior to Next.js 13.4 the primary routing was done through the Pages Router Static Generation (SSG) would be implemented as follow to get static data at build time so the data can be pre-rendered with the page.

// pages/todos.js
import { Amplify, API, graphqlOperation } from 'aws-amplify'
import { listTodos } from '../graphql/queries'
import awsExports from "../aws-exports"

Amplify.configure(awsExports)

export default function Todos(props) {
  const todos = props.data.listTodos.items
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.name}</li>
      ))}
    </ul>
  )
}

export async function getStaticProps() {
  const { data } = await API.graphql(graphqlOperation(listTodos))
  return { props: { data } }
}

To implement the page for Server-side Rendering (SSR), to get data on each request the same component can be used, but getServerSideProps would be used instead of getStaticProps and data will be fetched on the server and bundled with the initial render.

As of Next.js 13.4 the default routing is done via the App Router, first introduce in Next.js 13 and is built on React Server Components, which supports shared layouts, nested routing, loading states, error handling, and more.

Below, the component is adapted to show the async/await syntax for a React Server Component in Next.js 13.4 and higher, with the difference being that getStaticProps is no longer used and the awaited call to API.graphql is enclosed in the component definition.

// app/page.js
import { Amplify, API, graphqlOperation } from 'aws-amplify'
import { listTodos } from '../graphql/queries'
import awsExports from "../aws-exports"

Amplify.configure(awsExports)

export default async function Todos(props) {
  const { data } = await API.graphql(graphqlOperation(listTodos))
  const todos = data.listTodos.items
  
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.name}</li>
      ))}
    </ul>
  )
}

As a result, developers have all they need from the AWS Amplify Libraries and the client code generation provided by the Amplify CLI to query the Todos and render them with an interface that composes into either the Pages Router or App Router pattern for Next.js.

2. Authentication and Authorization

Next.js does not have a built-in authentication or authorization system, but with AWS Amplify, you can add user login, signup and management to your Next.js app using one of the supported authentication providers.

AWS Amplify works with authentication providers like Google, Facebook, etc. with Amazon Cognito as the main authentication provider. This allows you to quickly and easily implement auth flows like user login, signup, token refresh, and multi-factor authentication (MFA) in your Next.js app with a few lines of code and your users can sign in with a provider of their choice. The AWS Amplify Libraries will handle interacting with user pools, user credentials, and generating auth tokens to enable secured access to different parts of your app.

The Authenticator connected component from Amplify UI React adds complete authentication flows to your application with minimal boilerplate.  After configuring the AWS Amplify Libraries, a React application can be integrated with a few lines of code as illustrated below.

import { Amplify } from 'aws-amplify';

import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';

import awsExports from './aws-exports';
Amplify.configure(awsExports);

export default function App() {
  return (
    <Authenticator>
      {({ signOut, user }) => (
        <main>
          <h1>Hello {user.username}</h1>
          <button onClick={signOut}>Sign out</button>
        </main>
      )}
    </Authenticator>
  );
}

3. File Storage

While Next.js enables file-based routing, it does not provide cloud-based file storage. Amplify Storage lets you upload and manage user files like images, videos, audio, etc. to S3 buckets. This enables features like user file uploads, storing images for blog posts, hosting podcasts/videos, and more from your Next.js app. Amplify Storage supports uploading multiterabyte files to Amazon S3 such as large media files (PDFs, music, video and high resolution images) and the AWS Amplify Libraries handle generating signed upload URLs and download URLs so your Next.js app can upload and fetch files from S3 directly.  Add storage to a Next.js 13 app with AWS Amplify provides a walkthrough of adding storage to an app.

Furthermore, the Storage Manager component from Amplify UI is a cloud-connected UI component that lets your users upload and manage files directly to Amazon S3.  Details for using the Storage Manager can be found on the AWS Front-End Web & Mobile Blog in Announcing the Amplify UI StorageManager Component and for AWS Amplify StudioAnnouncing Storage Manager and Relationship Support for Form Builder.

4. Testing

AWS Amplify seamlessly integrates with Cypress, a popular end-to-end testing framework, to enable automated testing of web applications. Amplify Hosting can be setup to add end-to-end Cypress tests to your Amplify app during the test phase of your Amplify app to catch regressions before pushing code to production.

Details around implementing Cypress with AWS Amplify Hosting can be found in Automate Testing with Authentication using AWS Amplify and Cypress on the AWS Front-End Web & Mobile Blog.

5. Hosting

Next.js offers two main types of app rendering, Static Site Generation (SSG) and Server-side Rendering (SSR).

SSG renders pages at build time as static HTML files and serves them at request time. This is best for pages that do not require frequent updates and provides benefits like improved performance, SEO, and client-side caching.

SSR renders pages on the server at request time and sends the rendered HTML to the client. This is best for pages that require frequent updates or access to external data sources and provides benefits like being able to render data on the server and sending it in the initial HTML response.

Next.js lets you choose which rendering mode you want on a per-page basis.  Examples include using SSG only for marketing pages, SSR only for product pages that query a database or SSG for blog posts but SSR for the blog homepage that lists recent posts.

In addition, Next.js offers incremental static generation (ISR) and revalidation for pages using SSG. This allows you to statically generate pages at build time, then revalidate and re-generate them incrementally after build. So your pages benefit from fast initial load times (SSG) but can still be updated over time (revalidation).

Next.js also offers a “hybrid” rendering approach where it statically generates some data at build time but fetches additional data on the server at request time. So pages get SSG for some data and SSR for other parts of the page.

AWS Amplify Hosting, a fully managed CI/CD and hosting service for fast, secure, and reliable static and server-side rendered apps that scale with your business, supports deployment of Next.js applications to for all of these rendering strategies.  These strategies are covered a the series on the AWS Front-End Web & Mobile Blog around Next.js 13 apps including Deploy a Next.js 13 app with authentication to AWS AmplifyBuild a Product Roadmap with Next.js and Amplify and Add storage to a Next.js 13 app with AWS Amplify.