UNPKG

open-next-cdk

Version:

Deploy a NextJS app using OpenNext packaging to serverless AWS using CDK

279 lines (211 loc) 10.5 kB
<h1 align="center"> <div align="center"> <img align="middle" alt="Typescript" src="./resources/typescript.svg" width=15> <img align="middle" alt="Java" src="./resources/java.svg" width=20> <img align="middle" alt="Go" src="./resources/go.svg" width=30> <img align="middle" alt="Python" src="./resources/python.svg" width=15> <img align="middle" alt=".NET" src="./resources/dotnet.svg" width=30> </div> OpenNext CDK </h1> <div align="center"> <a href="https://github.com/datasprayio/open-next-cdk/actions?query=workflow%3A%22build%22"> <img align="middle" alt="Build Status" src="https://img.shields.io/github/actions/workflow/status/datasprayio/open-next-cdk/build.yml?style=for-the-badge"> </a> <a href="https://github.com/datasprayio/open-next-cdk/blob/master/LICENSE"> <img align="middle" alt="License" src="https://img.shields.io/github/license/datasprayio/open-next-cdk?style=for-the-badge"> </a> <a href="https://www.npmjs.com/package/open-next-cdk"> <img align="middle" alt="NPM release" src="https://img.shields.io/npm/v/open-next-cdk?label=RELEASE&color=blue&style=for-the-badge"> </a> </div> <h3 align="center">Deploy NextJS on AWS using CDK IaC and OpenNext packaging</h3> ### Contents - [What is this?](#what-is-this) - [Quickstart](#quickstart) - [Requirements](#requirements) - [Advanced](#advanced) - [Pre-built OpenNext package](#pre-built-opennext-package) - [Additional security](#additional-security) - [About](#about) - [Benefits](#benefits) - [Dependencies](#dependencies) - [Similar projects](#similar-projects) - [Fork from cdk-nextjs](#fork-from-cdk-nextjs) - [Contributing](#contributing) - [Using Projen](#using-projen) # What is this? A building block for Amazon's infrastructure-as-code CDK toolkit to deploy a NextJS app using AWS serverless services. Your NextJS app is packaged using OpenNext to fit the serverless format on Lambda # Requirements NextJs versions: >=12.3.0+ (includes 13.0.0+) Platforms: darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-arm64, win32-x64 # Quickstart ### NextJS setup Add a dev dependency `esbuild@0.17.16` to your NextJS project. ```shell npm install --save-dev esbuild@0.17.16 ``` ### CDK Construct Use this construct in your CDK application to deploy your NextJS app to AWS. <details> <summary>Typescript <img align="middle" alt="Typescript" src="./resources/typescript.svg" width=20></summary> <a href="https://www.npmjs.com/package/open-next-cdk"> <img align="middle" alt="NPM release" src="https://img.shields.io/npm/v/open-next-cdk?style=for-the-badge"> </a> Install the dependency using npm: ```shell npm install --save-dev esbuild@0.17.16 open-next-cdk ``` Use the construct in your CDK application: ```ts import { Nextjs } from 'open-next-cdk'; new Nextjs(this, 'Web', { nextjsPath: './web', // relative path to nextjs project root }); ``` </details> <details> <summary>Java <img align="middle" alt="Java" src="./resources/java.svg" width=20></summary> <a href="https://search.maven.org/artifact/io.dataspray/open-next-cdk"> <img align="middle" alt="Maven Central release" src="https://img.shields.io/maven-central/v/io.dataspray/open-next-cdk?style=for-the-badge"> </a> Install the dependency using Maven: ```xml <dependency> <groupId>io.dataspray</groupId> <artifactId>open-next-cdk</artifactId> <version>x.y.z</version> </dependency> ``` Use the construct in your CDK application: ```java Nextjs.Builder.create(this, getConstructId()) .nextjsPath("./web") .build(); ``` </details> <details> <summary>Go <img align="middle" alt="Go" src="./resources/go.svg" width=20></summary> <a href="https://github.com/datasprayio/open-next-cdk/tree/main/opennextcdk"> <img align="middle" alt="Go release" src="https://img.shields.io/github/go-mod/go-version/datasprayio/open-next-cdk/go?filename=opennextcdk%2Fgo.mod&label=GO&style=for-the-badge"> </a> Install the dependency: ```shell go get github.com:datasprayio/open-next-cdk.git@go ``` Or checkout [the code in the `go` branch](https://github.com/datasprayio/open-next-cdk/tree/go). </details> <details> <summary>Python <img align="middle" alt="Python" src="./resources/python.svg" width=20></summary> <a href="https://pypi.org/project/open-next-cdk/"> <img align="middle" alt="Pypi release" src="https://img.shields.io/pypi/v/open-next-cdk?style=for-the-badge"> </a> Install the dependency: ```shell pip install open-next-cdk ``` </details> <details> <summary>.NET <img align="middle" alt=".NET" src="./resources/dotnet.svg" width=20></summary> <a href="https://www.nuget.org/packages/Dataspray.OpenNextCdk"> <img align="middle" alt="Nuget release" src="https://img.shields.io/nuget/v/Dataspray.OpenNextCdk?style=for-the-badge"> </a> Install the dependency: ```shell dotnet add package Dataspray.OpenNextCdk ``` </details> <br/> This will automatically build your NextJS app and package it for you as part of the CDK construct. If you would prefer to package it separately, see below: # Advanced ### Pre-built OpenNext package <details> <summary>How-to</summary> You may also provide already pre-built OpenNext package directly by building it yourself first: ```shell open-next build ``` You will find a new folder `.open-next` which contains the packaging for your NextJS App. Now you can use the construct by instructing it not to build your app, just use the OpenNext folder directly: ```ts import { Nextjs } from 'open-next-cdk'; new Nextjs(this, 'Web', { openNextPath: './web/.open-next', // relative path to .open-next folder }); ``` </details> ### Additional security <details> <summary>How-to</summary> ```ts import { RemovalPolicy, Stack } from "aws-cdk-lib"; import { Construct } from "constructs"; import { CfnWebAcl } from "aws-cdk-lib/aws-wafv2"; import { SecurityPolicyProtocol, type DistributionProps } from "aws-cdk-lib/aws-cloudfront"; import { Nextjs, type NextjsDistributionProps } from "cdk-nextjs-standalone"; import { Bucket, BlockPublicAccess, BucketEncryption } from "aws-cdk-lib/aws-s3"; // Because of `WebAcl`, this stack must be deployed in us-east-1. If you want // to deploy Nextjs in another region, add WAF in separate stack deployed in us-east-1 export class UiStack { constructor(scope: Construct, id: string) { const webAcl = new CfnWebAcl(this, "WebAcl", { ... }); new Nextjs(this, "NextSite", { nextjsPath: "...", defaults: { assetDeployment: { bucket: new Bucket(this, "NextjsAssetDeploymentBucket", { autoDeleteObjects: true, removalPolicy: RemovalPolicy.DESTROY, encryption: BucketEncryption.S3_MANAGED, enforceSSL: true, blockPublicAccess: BlockPublicAccess.BLOCK_ALL, }), }, distribution: { functionUrlAuthType: FunctionUrlAuthType.AWS_IAM, cdk: { distribution: { webAclId: webAcl.attrArn, minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2021, } as DistributionProps, }, } satisfies Partial<NextjsDistributionProps>, }, }); } } ``` </details> <br /> # About Deploys a NextJs static site with server-side rendering and API support. Uses AWS lambda and CloudFront. There is a new (since Next 12) [standalone output mode which uses output tracing](https://nextjs.org/docs/advanced-features/output-file-tracing) to generate a minimal server and static files. This standalone server can be converted into a CloudFront distribution and a lambda handler that handles SSR, API, and routing. The CloudFront default origin first checks S3 for static files and falls back to an HTTP origin using a lambda function URL. ## Benefits This approach is most compatible with new NextJs features such as ESM configuration, [middleware](https://nextjs.org/docs/advanced-features/middleware), next-auth, and React server components ("appDir"). The unmaintained [@serverless-nextjs project](https://github.com/serverless-nextjs/serverless-next.js) uses the deprecated `serverless` NextJs build target which [prevents the use of new features](https://github.com/serverless-nextjs/serverless-next.js/pull/2478). This construct was created to use the new `standalone` output build and newer AWS features like lambda function URLs and fallback origins. You may want to look at [Serverless Stack](https://sst.dev) and its [NextjsSite](https://docs.sst.dev/constructs/NextjsSite) construct for an improved developer experience if you are building serverless applications on CDK. ## Dependencies Built on top of [open-next](https://open-next.js.org/), which was partially built using the original core of cdk-nextjs-standalone. ## Similar projects This project is heavily based on - [Open-next](https://open-next.js.org/) - <https://github.com/iiroj/iiro.fi/commit/bd43222032d0dbb765e1111825f64dbb5db851d9> - <https://github.com/sladg/nextjs-lambda> - <https://github.com/serverless-nextjs/serverless-next.js/tree/master/packages/compat-layers/apigw-lambda-compat> - [Serverless Stack](https://github.com/serverless-stack/sst) - [RemixSite](https://github.com/serverless-stack/sst/blob/master/packages/resources/src/NextjsSite.ts) construct - [NextjsSite](https://github.com/serverless-stack/sst/blob/master/packages/resources/src/RemixSite.ts) construct ### Fork from cdk-nextjs Compatible with: `cdk-nextjs`[@3.2.1](https://github.com/jetbridge/cdk-nextjs/releases/tag/v3.2.1) This project has been initially forked from [cdk-nextjs](https://github.com/jetbridge/cdk-nextjs) in order to [publish the package to other langugages](https://github.com/jetbridge/cdk-nextjs/issues/120#issuecomment-1634926223). So far notable changes are: - Extended language support: TS, Java, Go, .NET, Python. - Extended platform support: darwin-arm64, darwin-x64, linux-arm64, linux-x64, win32-arm64, win32-x64 - Use pre-built open-next package # Contributing Hey there, we value every new contribution a lot 🙏🏼 thank you. Open an issue or a PR and we'll gladly help you out. ## Using Projen Most boilerplate files are pre-generated including package.json. Don't update it directly, rather update `.projenrc.js` then run `yarn projen` to re-generate the files.