Deploy NextJS apps on AWS Amplify - Complete Guide

avatar

Borislav Hadzhiev

Mon Apr 26 20217 min read

Updated on Mon Apr 26 2021

A step by step guide on how to deploy static Next.js sites on AWS Amplify with automatic deployment on pushes to a Github master branch.

Table of Contents #

  1. Hosting Nextjs Sites on Amplify
  2. Prerequisites to hosting Nextjs sites on Amplify
  3. Amplify Hosting options
  4. Creating the Next.js application
  5. Initializing the Amplify project
  6. Adding Amplify hosting to the Nextjs Site
  7. Updating the Amplify Hosting 404 behavior
  8. Update the Node.js Version of the build env of Amplify
  9. Amplify invalidates cache instantly on deploys
  10. Testing our Github Pipeline
  11. Conclusion

Hosting Nextjs Sites on Amplify #

We are going to create a Next.js application and host it on AWS Amplify.

Every time we push changes to the master branch of our Github repository, Amplify will start an automated build and deploy process.

In order to deploy a Nextjs site to AWS Amplify, we have to execute the amplify add hosting command and pick between manually publishing updates to our site, or triggering changes on pushes to a git branch.

Prerequisites to hosting Nextjs sites on Amplify #

  1. Have the Amplify CLI installed and configured.

Amplify Hosting options #

There are 2 approaches:

  • CLI workflow - you manually publish changes to your live site
  • Git based workflow - pushes to your github repository initialize a build and deploy

In this article we'll use the Git based approach as it's automated.

When you merge changes into the master branch, amplify starts the build process. On a successful build, the application is deployed.

At the time of writing you can only host static Next.js sites on AWS Amplify

Creating the Next.js application #

Let's create a simple next application:

shell
npx create-next-app hello-world

Currently Amplify only supports static hosting of static Next.js applications, which means that we have to use the Static HTML Export feature.

After we export our application into static pages, we'll have generated all the necessary javascript, html, css, images and other assets that make up our application.

Note that there are many Next.js features that require a running server, for instance:

At the time of writing Next.js features that require a running server are not supported.

The next thing we should do is update our build script in package.json to export after build. Your scripts section should look like:

package.json
{
  "scripts": {
    "dev": "next dev",
    "build": "next build && next export",
    "start": "next start"
  }
}

Initializing the Amplify project #

First we'll initialize the Amplify project.

shell
amplify init

For most of the options Amplify should be able to infer the right choice. However set the distribution directory path to out - that's where next export spits out our static files.

QuestionAnswer
Enter a name for the projecthelloworld
Enter a name for the environmentdev
Choose your default editor:Visual Studio Code
What javascript framework are you using:react
Source Directory Path:src
Distribution Directory Path:out ๐Ÿ‘ˆ
Build Command:npm run-script build
Start Command:npm run-script start
Select the authentication method you want to useAWS profile

The only thing I had to change was set the Distribution Directory Path to out. For all other questions amplify was able to infer the right answer.

Here's a screenshot of my configuration:

amplify init

Adding Amplify hosting to the Nextjs Site #

shell
amplify add hosting
QuestionAnswer
Hosting with Amplify Console (Managed hosting ...)Yes

amplify add hosting 1

Click Enter to confirm on the Hosting with Amplify Console option.

QuestionAnswer
Choose a typeContinuous deployment (Git-based deployments)

amplify add hosting 2

Open another terminal tab and remove the default .git repository in the hello-world directory:

shell
rm -rf .git

Initialize a new git project and create a Github repository:

shell
git init

amplify hosting test

Add the remote:

shell
git remote add origin __YOUR_REMOTE_REPOSITORY__

Now add, commit and push:

shell
git add .
git commit -m 'initial commit'
git push --set-upstream origin master

Amplify should have opened a tab in your browser where you can see the services we can integrate with, in our case we chose Github.

Select the Frontend environments tab and Github and click Connect Branch: select github

If the tab with service integrations doesn't open, navigate to the amplify console by clicking the link - Amplify console

Authorize Amplify to access your github account's repositories and select the repository you pushed your next project to and click Next:

amplify connect github

On the next screen uncheck Backend Deployments option. We don't have a backend to deploy:

untick backend deployments

As the warning indicates now we should remove the aws-exports.js line from our .gitignore file:

.gitignore
- aws-exports.js

Leave the rest of the options as default and click Next.

On the next screen click Save and Deploy.

At this point every time we make changes to our master branch amplify will build and deploy our Next.js application.

After our build is complete you can click on the Mac window thingy or the link, to open your Next.js application.

build complete

Updating the Amplify Hosting 404 behavior #

At this point our next app is complete and we're able to access it, however what happens if we enter a URL path that doesn't exist.

For example if we navigate to /does-not-exist we simply get an Error:

Message - Access Denied

access denied

At this point if we try to go directly to a path on the site, that does not exist it returns unstyled XML content. This makes sense, because we're serving a static site that consists of html pages, we have to set a behavior for when the requested route doesn't exist.

The way to fix it is to add a custom redirect and redirect paths under a folder that can't be found to a custom 404 page.

Let's add a Redirect in our Amplify Rewrites and redirects configuration.

First open the Amplify Console. Select your Amplify application, and in the left navigation bar click on Rewrites and redirects.

Then click on Add rewrites and redirects.

  • from source address /<*> to target address /404.html with Type 404 (Rewrite), leave the other fields as empty and click Save.

404rewrite

Clear the browser cache and go to a non-existent path in your Next application and you should see the default 404 page:

404 page

Update the Node.js Version of the build env of Amplify #

On another project of mine, I deployed using Git-based workflow and pushed my code to Github - the build failed.

Turns out the version of Node.js used in the build environment was too old to be compatible for building tailwindcss v2. After my build failed I had to edit my Build settings and add an nvm install 14 step to the preBuild section.

In the Amplify console in the left sidebar click on Build Settings, then click Edit and add nvm install 14 to the commands in the preBuild section.

frontend:
  phases:
    preBuild:
      commands: ['nvm install 14', 'npm ci']

The entire amplify.yml file should look like:

version: 1
frontend:
  phases:
    preBuild:
      commands: ['nvm install 14', 'npm ci']
    build:
      commands: ['npm run build']
  artifacts:
    baseDirectory: out
    files:
      - '**/*'
  cache:
    paths:
      - 'node_modules/**/*'

This updates the node version in the build environment and fixed my issue with tailwind builds failing.

Amplify invalidates cache instantly on deploys #

The Amplify console offers instant cache invalidation by setting the header cache-control: max-age=0, which means that the browser asks the CDN if the files cached in the browser match the latest available version.

If the files match what's on the CDN - the browser serves the assets from its own cache. Otherwise the new assets are fetched from the origin (S3 Bucket).

If you want to cache more aggressively you could enable performance mode on a per branch basis. Performance mode optimizes for faster hosting performance by keeping content cached at the edge for longer, but code changes can take up to 10 minutes to roll out.

Testing our Github Pipeline #

When we push changes to the master branch our Amplify build process will start. After a successful build we'll be able to view our updated application immediately.

Open your pages/index.js file, make a change and push it to github to initialize a build and deployment.

pages/index.js
export default function Home() {
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <h1 className={styles.title}>๐Ÿ‘‰ Hosted on AWS Amplify ๐Ÿ‘ˆ</h1>
      </main>
      {/* ...rest */}
    </div>
)}

Now push the changes to Github:

shell
git add .
git commit -m 'updated index page'
git push

At this point if we open our Amplify console we can see that the build has been initialized:

build starting

After the build has succeeded we can open our application and see the changes have been applied instantly:

updated index page

Conclusion #

Hosting static sites on Amplify is pretty intuitive.

The git integration with automated builds on pushes to a particular branch abstracts away the complexity of managing a CICD pipeline.

Gone are the days where we had to manage cloudfront distributions and s3 buckets and do all that nasty stuff.

CloudFront distributions take about 30 minutes to deploy or update, so that's not very nice, especially when you're just starting out and don't know what you're doing.

Clean up #

To delete all resourced provisioned by our Amplify project, we can run:

shell
amplify delete

Further reading #

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee