How to Deploy a Next.js App with Custom Domain on AWS Using SST

Serverless architectures have transformed the way we build and deploy applications in the cloud, bringing in more efficiency and scalability.

In this blog, we dive into the Serverless Stack (SST), a framework for building serverless applications. We will deploy a Next.js application and set up a custom domain, all without ever visiting the AWS console. Let’s begin this journey!

What is Serverless?

Serverless is a cloud computing model where developers can build and deploy applications without the need to manage servers. In a serverless architecture, the cloud provider handles server provisioning, scaling, and maintenance, allowing developers to focus solely on writing code for their applications.

With serverless, developers are billed based on actual usage rather than fixed server costs, making it a cost-effective and scalable solution. It offers increased flexibility and agility, as resources are automatically allocated and released based on demand, eliminating the need for developers to worry about infrastructure management.

Now that we have a good idea of what is Serverless, let’s see what is Serverless Stack (SST)

Understanding Serverless Stack (SST)

Serverless Stack Toolkit, or SST in short, is a flexible, open-source framework designed to enable faster development and reliable deployment of serverless applications on AWS.

It aims to make it easier for developers to define their application’s infrastructure using AWS CDK (Cloud Development Kit), test applications in real-time with Live Lambda Development, debug code in Visual Studio Code, manage applications through a web-based dashboard, and deploy to multiple environments and regions seamlessly

Benefits of Using SST

Infrastructure as Code

With SST, developers can define their application’s infrastructure programmatically using AWS CDK, which improves version control and collaboration among team members.

Efficient Testing and Debugging

SST enables live Lambda development, making it easier to test and debug serverless applications locally before deployment to AWS, thus reducing potential issues and ensuring smoother deployment.

Simplified Deployment

SST simplifies the deployment process, allowing developers to deploy applications to multiple environments and regions effortlessly.

Language Flexibility

SST supports multiple programming languages, including JavaScript, TypeScript, Go, Python, C#, and F#, providing developers with the flexibility to use their preferred language for building serverless applications.

Now we have understood what is SST and some of its benefits, let’s see the power of SST in action.

Configure AWS

Before we add SST we have to configure AWS credentials. Type the below command in the terminal

aws configure

It will ask you AWS Access Key ID, Secret Access Key, Region name and output format. If you don’t have these keys, please create an IAM user and enter the credentials.

How to add SST to NextJS app

We can use SST in an existing NextJS app in drop-in mode or inside a monorepo app in standalone mode.

In this blog, we’ll create new NextJS project and add SST which follows drop-in mode installation.

yarn create next-app
cd my-app
yarn create sst
yarn install

Note: You should find index.tsx file inside /pages folder. Ensure it is available, if not you’ll get errors while deploying your app using SST. You don’t need to make any changes to this file.

Once you run the above commands SST will create two new files, namely sst.config.ts and sst-env.d.ts

We have to define all our infrastructure and stacks in sst.config.ts file.

Let’s try to run the app in our local machine,

# Start SST locally
yarn sst dev
# Start NextJS locally
yarn dev

On executing yarn sst dev command, you’ll be asked to enter the stage name. Please enter your environment name. I’m entering it as dev.

Just sit back and watch. It will automatically create the necessary IAM roles, permissions and CloudFormation stacks.

If you notice in the terminal (above image), you should be able to see a console URL. With the Console URL, you can view real-time logs, invoke functions, replay invocations, make queries, run migrations, view uploaded files, query your GraphQL APIs, and more!

Just awesome right? I would recommend you to visit the offical documentation to learn more about the services they offer.

Start the NextJS site by running yarn dev, you should see the default page.

Our NextJS app is now ready to be deployed to AWS! Just run the following command and see the magic.

yarn sst deploy --stage prod

It will automatically start building the app using OpenNext , deploy it to AWS using CDK, and output the Cloudfront URL. Click on the link and you should be able to see our app up and running.

How to create Infrastructure using SST

To create an Infrastructure we simply need to edit sst.config.ts and import any AWS services like S3 bucket, RDS, API Gateway etc.., from sst/constructs

Let’s add a simple S3 file upload feature. Open sst.config.ts file and add the below code.

import { SSTConfig } from "sst";
import {Bucket, NextjsSite } from "sst/constructs";

export default {
  config(_input) {
    return {
      name: "sst-tutorial",
      region: "us-east-1",
    };
  },
  stacks(app) {
    app.stack(function Site({ stack }) {
      const bucket = new Bucket(stack, "public");
      const site = new NextjsSite(stack, "site",{
        bind:[bucket],
      });
      stack.addOutputs({
        SiteUrl: site.url,
      });
    });
  },
} satisfies SSTConfig;

Here, we’re creating a new public S3 bucket and binding it with our NextjsSite

Let’s edit our index page to add file upload feature.

How to upload files to S3 using SST

To upload a file to S3 we need to generate a pre-signed URL. To do that, we need to add this package @aws-sdk/s3-request-presigner in our repo.

yarn add @aws-sdk/s3-request-presigner

Open index.tsx file, create function called getServerSideProps, above the Home function, as shown in the below code snippet.

...
import { Bucket } from "sst/node/bucket";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
...
export async function getServerSideProps() {
  const command = new PutObjectCommand({
    ACL: "public-read",
    Key: crypto.randomUUID(),
    Bucket: Bucket.public.bucketName,
  });
  const url = await getSignedUrl(new S3Client({}), command);
  const bucketName = Bucket.public.bucketName
  console.log(bucketName)
  return { props: { url } };
}

Update the Home() function with the following code.

I added a file upload input and a button to submit. Upon submitting the selected image will be uploaded to S3. It’s time to deploy the changes.

To deploy the changes run yarn sst deploy.

Once deployed you can see the below page.

Now upload any image and check your S3, selected file will be uploaded in your S3 bucket.

Great, we have successfully deployed the changes. But still, we have URL generated by CloudFront which is a random string and not rememberable by humans. Let’s configure a custom domain.

How to configure custom domains

To configure custom domains, we need a valid domain or sub-domain. If you don’t have a domain create one using Route 53 or your preferred domain provider (Eg. GoDaddy).

If you have a domain in an external DNS provider you need to create a SSL certificate on AWS Certificate Manager (ACM)

I’ve my domain in Cloudflare, if you have any other DNS providers like Namecheap or GoDaddy, don’t worry. The below steps are same for all DNS providers.

How to point CNAME to CloudFront

  1. Login into your DNS provider
  2. Add a CNAME, in my case, I gave the name as aws because my domain is aws.gogosoon.com and target as CloudFront URL without https.

We successfully pointed our CNAME to CloudFront. Now let’s create a SSL certificate for our domain.

How to create ACM certificate

Note: CloudFront will check the certificate only on us-east-1 region, so switch to us-east-1 region.

  1. Login into AWS console
  2. Search for certificate manager and click on Request Certificate in the sidebar.

3. Enter the domain name you pointed, in your DNS provider, select Email validation for Validation method, and click next

4. A certificate with the status Pending Validation will be created. Now you would have received an email from AWS, click on the link to validate the request.

5. Once you click on the link in the email, the status of the certificate will be changed to Issued. Copy the ARN, we need it in the next steps.

Now, we have created the certificate successfully! Lets create the alternate domain for CloudFront.

How to create an alternate domain for CloudFront distribution

  1. Login into AWS Console and search for CloudFront
  2. Click on the distribution created by SST
  3. In the General tab, click Edit button

4. Enter the Alternate domain name, select the certificate that we have created, leave all other options as default and click on “Save changes” button

All set! let’s edit our app to deploy the changes to our custom domain.

Configure external custom domain using SST

Update the sst.config.ts file with the following code. Paste the ARN you copied while creating the certificate as a value for the variable certArn. Replace the domainName with your domain

import { SSTConfig } from "sst";
import {Bucket, NextjsSite } from "sst/constructs";
import { Certificate } from "aws-cdk-lib/aws-certificatemanager";


export default {
  config(_input) {
    return {
      name: "sst-tutorial",
      region: "us-east-1",
    };
  },
  stacks(app) {
    app.stack(function Site({ stack }) {
      const bucket = new Bucket(stack, "public");
      const certArn = 'Paste the certificate arn'
      const site = new NextjsSite(stack, "site",{
        bind:[bucket],
        customDomain: {
          isExternalDomain: true,
          domainName: "aws.gogosoon.com",
          cdk: {
            certificate: Certificate.fromCertificateArn(stack, "MyCert", certArn),
          },
        },
      });
      stack.addOutputs({
        SiteUrl: site.customDomainUrl || site.url,
      });
    });
  },
} satisfies SSTConfig;

Run yarn sst deploy to deploy the changes to a custom domain. Once deployed when you hit your custom URL you should see our application running there.

Conclusion

Voila! Our Next.js app is now deployed to AWS, and we’ve connected it with our custom domain. Please check out the source code here.

The SST framework provides an excellent toolset for deploying serverless applications, contributing significantly to development speed, scalability, and error handling.

Feel free to explore more about SST and its potential in transforming your cloud development experience. Happy coding!

If you wish to learn more about AWS, subscribe to my newsletter by entering your email address in the below box.

Have a look at my site which has a consolidated list of all my blogs.

Share this article