cdklabs / cdk-nextjs

Deploy Next.js on AWS with CDK
https://constructs.dev/packages/cdk-nextjs
Apache License 2.0
5 stars 1 forks source link
aws cdk ecs-fargate lambda nextjs nodejs react

Version npm version License

CDK Next.js Construct Library


cdk-constructs: Experimental

The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the Semantic Versioning model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package.


Deploy Next.js apps on AWS with the AWS CDK.

Features

Getting Started

  1. If you don’t have a Next.js project yet, follow these steps to create one.
  2. Install Docker. We recommend Rancher Desktop with dockerd (moby) container engine enabled.
  3. Install Node.js. We recommend the long term support (LTS) version.
  4. Set your next.config.js output key to "standalone". Learn more here about Standalone Output.
  5. Setup AWS Cloud Development Kit app.
  6. Install the construct package: npm install cdk-nextjs
  7. cdk deploy
  8. Visit URL printed in terminal (CloudFormation Output) to view your Next.js app!

Basic Example CDK App

import { App, Stack } from "aws-cdk-lib";
import { Construct } from "constructs";
import { fileURLToPath } from "node:url";
import { NextjsGlobalFunctions } from "cdk-nextjs";

class NextjsStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id, props);
    new NextjsGlobalFunctions(this, "Nextjs", {
      healthCheckPath: "/api/health",
      buildContext: fileURLToPath(new URL("..", import.meta.url)),
    });
  }
}

const app = new App();

new NextjsStack(app, "nextjs");

See examples/ for more usage examples.

Architecture

NextjsGlobalFunctions

Architecture includes AWS Lambda Functions to respond to dynamic requests and CloudFront Distribution to globally serve requests and distribute static assets. Use this construct when you have unpredictable traffic, can afford occasional latency (i.e. cold starts - typically 1% of production traffic), and/or want the most granular pricing model. (code)

NextjsGlobalFunctions

NextjsGlobalContainers

Architecture includes ECS Fargate containers to respond to dynamic requests and CloudFront Distribution to globally serve requests and distribute static assets. Use this option when you have predictable traffic, need the lowest latency, and/or can afford a less granular pricing model. (code)

NextjsGlobalContainers

NextjsRegionalContainers

Architecture includes ECS Fargate containers to respond to dynamic requests and Application Load Balancer to regionally serve requests. Use this options when you cannot use Amazon CloudFront (i.e. AWS GovCloud). (code)

NextjsRegionalContainers

Why

The simplest path to deploy Next.js is on Vercel - the Platform-as-a-Service company behind Next.js. However, deploying to Vercel can be expensive and some developers want all of their workloads running directly on AWS. Developers can deploy Next.js on AWS through AWS Amplify Hosting, but Amplify does not support all Next.js features and manages AWS resources for you so they cannot be customized. If Amplify meets your requirements we recommend you use it, but if you want to use all Next.js features or want more visibility into the AWS resources then this construct is for you.

Design Principles

Limitations

Additional Security Recommendations

This construct by default implements all AWS security best practices that a CDK construct library reasonably can considering cost and complexity. Below are additional security practices we recommend you implement within your CDK app. Please see them below:

Estimated Costs

WIP

Contributing

Steps to build locally:

  1. git clone https://github.com/cdklabs/cdk-nextjs.git
  2. cd cdk-nextjs
  3. pnpm i && pnpm compile && pnpm build

This project uses Projen, so make sure to not edit Projen created files and only edit .projenrc.ts.

FAQ

Q: How does this compare to cdk-nextjs-standalone? A: cdk-nextjs-standalone relies on OpenNext. OpenNext injects custom code to interact with private Next.js APIs. While OpenNext is able to make some optimizations that are great for serverless environments, this comes at an increase maintenance cost and increased chances for breaking changes. A goal of cdk-nextjs is to customize Next.js as little as possible to reduce the maintenance burden and decrease chances of breaking changes.

Q: Why not offer API Gateway version of construct? A: API Gateway does not support streaming.

Q: Why EFS instead of S3? A: Next.js has 3 types of server caching that are persisted to disk: Data Cache, Full Route Cache, and Image Optimization. Cached data is persisted at .next/cache/fetch-cache, cached full routes are persisted at .next/server/app, and optimized images are persisted at .next/cache/images. Next.js provides a way to customize where cached data or cached full routes are persisted through the Custom Next.js Cache Handler, but there currently is no way to persist optimized images. Therefore, we need a way to persist cached data at the file system level which is transparent to Next.js. To do this, we use Amazon Elastic File System (EFS). Benefits of EFS include being able to cache any Next.js data persisted to disk and therefore being flexible to adapt to Next.js as the framework evolves caching additional types of data. One exception to not using the Custom Next.js Cache Handler is to support Data Cache Time-based Revalidation when using AWS Lambda functions. Functions only run when they are responding to a request preventing time-based revalidation unlike containers with AWS Fargate which run continually. For functions, an Amazon SQS Queue and consuming function that will make a HEAD request with x-prerender-revalidate header needed for Next.js to update cache.

Q: How customizable is the cdk-nextjs package for different use cases? A: The cdk-nextjs package offers deep customization through prop-based overrides. These can be accessed in the construct props, allowing you to override settings like VPC configurations, CloudFront distribution, and ECS/Fargate setup. For example, you can modify nextjsBuildProps to customize the build process or use nextjsDistributionProps to adjust how CloudFront handles caching and routing. This level of control makes it easy to adapt the infrastructure to your application’s specific performance, networking, or deployment needs.

Q: How can I use a custom domain with cdk-nextjs? A: To use a custom domain, you can configure the distribution prop within constructs like NextjsGlobalFunctions or NextjsGlobalContainers. By providing an ACM certificate and overriding relevant properties such as nextjsDistributionProps, you can customize the CloudFront distribution to handle your domain. This allows CloudFront to route traffic through your custom domain while managing SSL termination for secure HTTPS connections.

Acknowledgements

This construct was built on the shoulders of giants. Thank you to the contributors of cdk-nextjs-standalone and open-next.

🥂 Thanks Contributors

Thank you for helping other developers deploy Next.js apps on AWS