Deploy Nest JS on AWS

Deploy your Nest JS app on AWS with Lambda and API Gateway using the AWS CDK.

There are a few ways to deploy your Nest JS app on AWS:

  1. Standard Lambda and API Gateway.

  2. Node.js runtime container image on Lambda.

  3. Bun runtime container image on Lambda.

  4. One-click installation on your AWS account using Thunder console.

View code in StackBlitz

Deploy Nest JS on AWS Lambda + API Gateway


CDK Functions is a package that simplifies the deployment of Lambdas using the AWS Cloud Development Kit (CDK). It provides a straightforward way to deploy your Nest JS app to AWS Lambda and API Gateway.

1. Create a project

You can create a new Nest JS project using the following commands:

Terminal window
npm create nestjs@latest my-nestjs-app
cd my-nestjs-app

2. Initialize your project

Install the necessary dependencies and initialize your project:

Terminal window
npm i tsx aws-cdk-lib @thunderso/cdk-functions --save-dev

3. Create a CDK stack and Lambda handler

Create a stack/index.ts file to create your CDK stack. Edit it to match your project:

stack/index.ts
import { App } from "aws-cdk-lib";
import { Runtime, Architecture} from 'aws-cdk-lib/aws-lambda';
import { FunctionStack, type FunctionProps } from '@thunder-so/cdk-functions';
const fnStack: FunctionProps = {
env: {
account: '4477996600XX',
region: 'us-east-1',
},
application: 'nestjs',
service: 'api',
environment: 'dev',
functionProps: {
codeDir: 'dist',
handler: 'lambda-node.handler',
include: [
'node_modules', // Include node_modules for dependencies
'lambda-node.js', // Include the Lambda handler file
],
exclude: ['node_modules/.npmignore', '**/*.ts', '**/*.map'],
},
};
new FunctionStack(new App(),
`${fnStack.application}-${fnStack.service}-${fnStack.environment}-stack`,
fnStack
);

Create a lambda-node.js file in the root directory to handle the Lambda function:

src/lambda-node.js
const { NestFactory } = require('@nestjs/core');
const { AppModule } = require('./app.module');
const { configure } = require('@vendia/serverless-express');
let cachedServer;
async function bootstrapServer() {
if (!cachedServer) {
const app = await NestFactory.create(AppModule);
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
cachedServer = configure({ app: expressApp });
}
return cachedServer;
}
exports.handler = async (event, context) => {
const server = await bootstrapServer();
return server(event, context);
};

4. Deploy

Before you deploy, run your build script to generate artifacts in the dist directory.

Terminal window
npm run build

By running the following script, the CDK stack will be deployed to AWS.

Terminal window
npx cdk deploy --all --app="npx tsx stack/index.ts"

When the deployment is complete, you will see the API Gateway URL in the output. You can access your Nest JS app at that URL.

For complete documentation, refer to the CDK Functions documentation.

Node.js runtime container image on Lambda


You can also deploy your Nest JS app on AWS Lambda using a Node.js container image. This method allows you to package your application and its dependencies into a Docker image, which can then be deployed to AWS Lambda.

1. Create a lambda handler

Create a lambda-node.js file in the root directory to handle the Lambda function:

const { NestFactory } = require('@nestjs/core');
const { AppModule } = require('./app.module');
const { configure } = require('@vendia/serverless-express');
let cachedServer;
async function bootstrapServer() {
if (!cachedServer) {
const app = await NestFactory.create(AppModule);
await app.init();
const expressApp = app.getHttpAdapter().getInstance();
cachedServer = configure({ app: expressApp });
}
return cachedServer;
}
exports.handler = async (event, context) => {
const server = await bootstrapServer();
return server(event, context);
};

2. Create a Dockerfile

Create a Dockerfile.node in the root directory to build your Nest JS app as a container image:

FROM public.ecr.aws/lambda/nodejs:22 AS base
WORKDIR ${LAMBDA_TASK_ROOT}
# Copy dist files and install dependencies
COPY . .
RUN npm install --omit=dev
# Set the Lambda handler
CMD [ "lambda-node.handler" ]

Create/modify your CDK stack

Create a stack/node.ts file (or modify your existing stack/index.ts) to define your CDK stack:

stack/node.ts
const fnStack: FunctionProps = {
// ... other props
functionProps: {
codeDir: 'dist',
include: [
'package.json', // Include package.json for dependencies
'lambda-node.js' // Include the Lambda handler file
],
dockerFile: 'Dockerfile.node',
},
};

By running the following script, the CDK stack will be deployed to AWS.

Terminal window
npx cdk deploy --all --app="npx tsx stack/node.ts"

Bun runtime container image on Lambda


You can also deploy your Nest JS app on AWS Lambda with custom Bun runtime.

1. Create a lambda handler

Create a lambda-bun.js file in the root directory to handle the Lambda function:

lambda-bun.js
const { NestFactory } = require('@nestjs/core');
const { AppModule } = require('./app.module');
let app, expressApp;
async function getExpressApp() {
if (!expressApp) {
app = await NestFactory.create(AppModule);
await app.init();
expressApp = app.getHttpAdapter().getInstance();
}
return expressApp;
}
exports.fetch = async (request /*: Request*/, server /*: Server*/) => {
const expressApp = await getExpressApp();
// Convert Bun's Request to Node.js req/res for Express
// Use 'node-fetch' Response to Express bridge
const { Readable } = require('stream');
const { Headers } = require('node-fetch');
// Create a mock req object
const url = new URL(request.url);
const req = new Readable();
req.url = url.pathname + url.search;
req.method = request.method;
req.headers = Object.fromEntries(request.headers.entries());
req._read = () => {};
if (request.body) {
const body = Buffer.from(await request.arrayBuffer());
req.push(body);
}
req.push(null);
// Create a mock res object
return new Promise((resolve) => {
const chunks = [];
const res = {
statusCode: 200,
headers: {},
setHeader(key, value) { this.headers[key] = value; },
getHeader(key) { return this.headers[key]; },
write(chunk) { chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)); },
end(chunk) {
if (chunk) this.write(chunk);
const body = Buffer.concat(chunks);
resolve(
new Response(body, {
status: res.statusCode,
headers: res.headers,
})
);
},
status(code) { this.statusCode = code; return this; },
send(body) { this.end(body); },
};
expressApp(req, res);
});
};

2. Create a Dockerfile

Create a Dockerfile.bun in the root directory to build your Nest JS app as a container image with Bun runtime:

# Builder image
FROM oven/bun:latest AS bun
WORKDIR /tmp
## Install the bun dependencies
RUN apt-get update && apt-get install -y curl
RUN curl -fsSL https://raw.githubusercontent.com/oven-sh/bun/main/packages/bun-lambda/runtime.ts -o /tmp/runtime.ts
RUN bun install aws4fetch
RUN bun build --compile runtime.ts --outfile bootstrap
# Runtime image
FROM public.ecr.aws/lambda/provided:al2023
WORKDIR ${LAMBDA_TASK_ROOT}
## Copy bun + bootstrap from the builder image
COPY --from=bun /usr/local/bin/bun /opt/bun
COPY --from=bun /tmp/bootstrap ${LAMBDA_RUNTIME_DIR}
## Copy dist files and install dependencies
COPY . .
RUN /opt/bun install --frozen-lockfile
# Set our handler method
CMD [ "lambda-bun.fetch" ]

3. Create/modify your CDK stack

Create a stack/bun.ts file to define your CDK stack:

stack/bun.ts
const fnStack: FunctionProps = {
// ... other props
functionProps: {
codeDir: 'dist',
include: [
'package.json', // Include package.json for dependencies
'bun.lock', // Include bun.lock for Bun dependencies
'lambda-bun.js' // Include the Lambda handler file
],
dockerFile: 'Dockerfile.bun',
},
};

By running the following script, the CDK stack will be deployed to AWS.

Terminal window
npx cdk deploy --all --app="bunx tsx stack/bun.ts"