Borislav Hadzhiev
Mon Apr 26 2021·7 min read
Photo by Joanna Kosinska
Updated - Mon Apr 26 2021
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 run the
amplify add hosting
command and pick between manually publishing updates to
our site, or triggering changes on pushes to a git branch.
There are 2 approaches:
publish
changes to your live sitepushes
to your github repository initialize a build
and deployIn 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.
static
Next.js sites on AWS AmplifyLet's create a simple next application:
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:
{ "scripts": { "dev": "next dev", "build": "next build && next export", "start": "next start" } }
First we'll initialize the Amplify project.
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.
Question | Answer |
---|---|
Enter a name for the project | helloworld |
Enter a name for the environment | dev |
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 use | AWS 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 add hosting
Question | Answer |
---|---|
Hosting with Amplify Console (Managed hosting ...) | Yes |
Click Enter
to confirm on the Hosting with Amplify Console option.
Question | Answer |
---|---|
Choose a type | Continuous deployment (Git-based deployments) |
Open another terminal tab and remove the default .git
repository in the
hello-world
directory:
rm -rf .git
Initialize a new git project and create a Github repository:
git init
Add the remote:
git remote add origin __YOUR_REMOTE_REPOSITORY__
Now add, commit and push:
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:
Authorize Amplify to access your github account's repositories and select the repository you pushed your next project to and click Next:
On the next screen uncheck Backend Deployments option. We don't have a backend to deploy:
As the warning indicates now we should remove the aws-exports.js
line from our
.gitignore
file:
- 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.
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:
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.
Clear the browser cache and go to a non-existent path in your Next application and you should see the default 404 page:
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.
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.
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.
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:
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:
After the build has succeeded we can open our application and see the changes have been applied instantly:
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.
To delete all resourced provisioned by our Amplify project, we can run:
amplify delete