In the ever-evolving world of web development, deploying applications has become increasingly complex. However, with the rise of serverless architectures and powerful cloud platforms like Amazon Web Services (AWS), the process of deploying and scaling applications has become more streamlined and efficient than ever before. In this article, we will explore how to leverage AWS Lambda Web Adapter, Terraform, and AWS Lambda in combination with CloudFront to deploy a simple Next.js application.
Setting up NextJS app for standalone deployment
To create a new Next.js project, run the following command in your terminal:
Once the project is set up, you'll need to make a couple of modifications in the
next.config.js file to prepare the application for standalone deployment and utilize static files from a CDN. Open the
next.config.js file and add the following code:
standalone, Next.js can automatically create a standalone folder that copies only the necessary files for a production deployment, including select files in node_modules.
assetPrefix property should be set to the URL of your desired CDN. By doing so, your Next.js app will utilize the CDN to serve static files, resulting in improved performance and faster load times for your users.
Remember to replace
<CDN_URL> with the actual URL of your CDN. Once you've made these changes, your Next.js application will be ready for deployment using AWS Lambda and a CDN.
Provisioning infrastructure with Terraform
To deploy the Next.js app, we need to provision specific infrastructure components like a Lambda function with an API Gateway for the server, as well as a CloudFront distribution to handle static files. In this guide, we will focus on packaging the code as a zip file and utilizing it in a Lambda function. If you prefer using a Docker image, please refer to the official documentation for detailed instructions.
Before we begin, make sure you have Terraform and the AWS CLI installed. If you haven't already, you can follow the links below to install them:
Now, let's set up the necessary Terraform files. Create a new folder named
nextjs-lambda/ in the root directory of your application, and place the following files inside:
nextjs-lambda ├── api_gw.tf ├── cloudfront.tf ├── deploy.sh ├── domain.tf ├── lambda.tf ├── main.tf ├── output.tf ├── run.sh ├── s3_bucket.tf ├── terraform.tfvars ├── terraform.tfvars.example └── variables.tf
These files contain the Terraform configurations needed to provision the required AWS resources. The
main.tf file acts as the entry point for Terraform, and the other files define specific resources like API Gateway, CloudFront, Lambda function, and more.
Sets up the providers and remote state management in
main.tf. Here, the state is managed using S3 and Dynamodb. You can configure it to use other state management methods as well.
lambda.tf file is responsible for declaring the Lambda function, its policy, and CloudWatch logs. It utilizes the
archive_file module to create a zip file of the Next.js package.
- The Lambda handler in the code utilizes the
run.shbash script to initialize the server.
- To make this entire setup work, we rely on the Lambda Web Adapter layer. The layer is available in different architectures, and further details can be found in the official documentation.
- Additionally, you need to configure the Lambda environment variable
/opt/bootstrap. In the above example, this value is passed as a Terraform variable.
API Gateway enables us to invoke Lambda functions using a custom domain. In this example, Terraform is used to set up an HTTP API Gateway and grant it permission to invoke Lambda.
This section sets up a private S3 bucket and grants permission to access its contents via CloudFront.
CloudFront distribution is created with the S3 bucket as the source. Managed policies and other essential configurations are defined. Origin Access Control (OAC) is used to access the S3 bucket content.
This section is responsible for creating and assigning custom domains for API Gateway and CloudFront distribution. It utilizes an existing Hosted Zone and SSL Certificate. For API Gateway, a custom domain is mapped to the HTTP API gateway with the default stage.
All the variables used in this Terraform module:
terraform.tfvars file is used to store variable values for the Terraform configuration. You can create it based on the provided
terraform.tfvars.example file and fill in the necessary values.
Returns the CDN domain and API Gateway domain
With the infrastructure provisioning files in place, we are ready to move on to the next steps of deploying the Next.js app using AWS Lambda and CloudFront.
run.sh bash script to the
nextjs-lambda/ folder, which will serve as the entry point to run the app after deployment.
In addition, include another bash script called
deploy.sh that packages files, provisions the infrastructure, and uploads static files to S3. Remember to update the
CDN_NAME variable (which must match the one used for infrastructure). Ensure that these bash scripts have execution permissions.
To deploy the app, execute the
deploy.sh bash script with argument
Note that even after the deployment is complete, it may take some time for the CloudFront deployment to finish.
To just sync files to Lambda and S3, execute the
deploy.sh bash script with argument
To destroy the deployment, navigate to the
nextjs-lambda/ folder and run:
Remember to add this to the
.gitignore file before committing any changes to Git.
You can find the code and an example in this GitHub repository