DEV Community

Cover image for Deploy Static Next.js App to S3 Bucket
Vladimir Vovk
Vladimir Vovk

Posted on

Deploy Static Next.js App to S3 Bucket

Let's deploy a static Next.js app to an S3 Bucket. I will use Yandex Object Storage (an S3-compatible service by Yandex). But it could be any S3 service and any "static" web app (Vite React, bare HTML, etc.); the process will be very similar.

Create Next.js App

bun create next-app
Enter fullscreen mode Exit fullscreen mode

Check everything works as expected by running the dev server:

bun run dev
Enter fullscreen mode Exit fullscreen mode

Now we need to change the next.config.ts to:

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  // cacheComponents: true,
  // partialPrefetching: true,
  output: 'export',
  distDir: 'dist',
  trailingSlash: true
};

export default nextConfig;
Enter fullscreen mode Exit fullscreen mode

We enabled the static export by setting output: 'export'. Also, the output folder was changed to dist (instead of out by default). We also need trailingSlash: true to make the Next.js routes work without the server (change links from /me -> /me/ and emit /me.html -> /me/index.html). Please see the docs for more details.

Let's build the app:

bun run build
Enter fullscreen mode Exit fullscreen mode

The dist folder should appear.

dist folder

Yandex Cloud Console

Open the Yandex Cloud Console.

Yandex Cloud Console

Go to the Object Storage.

Object Storage

Create a new bucket (set Read objects -> For all).

New bucket

Click the bucket you created. Go to Settings -> Website -> turn on Hosting. Set the Home page and Error page values and click Save.

Hosting settings

Now our bucket is ready. 🎉

Deployment Script

Let's write a script to automate our deployment process. First, to be able to upload files to the bucket, we need a static key.

Create a Service Account and Assign Roles

  1. Navigate to Identity and Access Management -> Service accounts.

Identity and Access Management

  1. Click Create service account, name it (for example, s3-copy-sa), and click Create.
  2. Assign the storage.editor role to the service account so it can manage and upload objects to your bucket.

Create the Static Access Key

  1. In the Service accounts list, select your newly created service account.
  2. In the top panel, click Create new key and select Create static access key.
  3. Add a description (optional) and click Create.
  4. Important: Copy and save the Key ID and the Secret Key immediately. You will not be able to view the secret key again once you close the window.

Create the secrets/.env.deploy file:

export BUCKET_NAME=your-bucket-name
export AWS_ACCESS_KEY_ID=your-access-key-id
export AWS_SECRET_ACCESS_KEY=your-access-key
export AWS_DEFAULT_REGION=ru-central1
export AWS_ENDPOINT_URL=https://storage.yandexcloud.net/
Enter fullscreen mode Exit fullscreen mode

Add secrets/* to .gitignore so your secrets will never be committed to your git repository.

Create Script

Create the scripts/deploy.sh file:

source ./secrets/.env.deploy

dist_folder="dist"

is_dist_exists=0
if [ -d $dist_folder ]; then
    is_dist_exists=1
fi

should_rebuild=1
if [ $is_dist_exists -ne 0 ]; then
    echo ""
    read -p " 🚧 The \"$dist_folder\" (build) folder already exists. Rebuild the project? (y/n): " confirm

    if [ "$confirm" == "n" ]; then
        should_rebuild=0
    fi
fi

if [ $should_rebuild == 1 ]; then
    echo ""
    echo " 🏗️ building..."
    echo ""

    bun run build
    build_status=$?
else
    build_status=0
fi

if [ $build_status -ne 0 ]; then
    echo ""
    echo " 🚨 Build failed!"
    echo ""
    exit $build_status
fi


echo ""
read -p " 🛳️ Deploy to production? (y/n): " confirm

if [ "$confirm" != "y" ]; then
    echo " 🚫 Deploy canceled."
    echo ""
    exit 1
fi

echo ""
echo " ☕"
echo ""

echo ""
echo " Backup old files..."
echo ""

(aws s3 --recursive mv s3://$BUCKET_NAME/ "s3://$BUCKET_NAME.backup/$(date +%Y-%m-%d_%H-%M-%S)/")

echo ""
echo "Copying new files..."
echo ""

(aws s3 --recursive cp $dist_folder s3://$BUCKET_NAME/)

unset BUCKET_NAME
unset AWS_ACCESS_KEY_ID
unset AWS_SECRET_ACCESS_KEY
unset AWS_DEFAULT_REGION
unset AWS_ENDPOINT_URL

echo ""
echo " 🚀 Done!"
echo ""
Enter fullscreen mode Exit fullscreen mode

This script will check if the dist folder exists. Ask whether we need to rebuild the project. Back up the old deployment to the BACKET_NAME.backup bucket. And upload the current build to the BUCKET_NAME bucket.

Please create the BUCKET_NAME.backup bucket. For example, if your bucket name is static-app, then create the static-app.backup bucket.

Also, install the aws-cli command-line tool. We will need it to manipulate our buckets. See the docs for more info.

curl -fsSL https://awscli.amazonaws.com/v2/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

Make it Live

Let's allow our script to be executed:

chmod +x scripts/deploy.sh
Enter fullscreen mode Exit fullscreen mode

And now we are ready to run it:

./scripts/deploy.sh
Enter fullscreen mode Exit fullscreen mode

After the script finishes, we should see our build files inside the bucket.

Bucket with build files

Go to the Settings tab -> Website and click the Link (https://your-bucket-name.website.yandexcloud.net).

Website settings

Congratulations, the app is live now! 🥳

Credits

Photo by Sixteen Miles Out on Unsplash.

Top comments (0)