Deploy NestJS Application as AWS Lambda using SAM CLI

Mohammed Adil
8 min readSep 15, 2023

--

NestJS + AWS Lambda using SAM

Hello, fellow tech enthusiasts! Are you ready to embark on a journey into the world of serverless computing? Our company recently set its sights on the magical realm of AWS Lambda, and I, your humble narrator, was tasked with the mission of deploying a NestJS application.

What is Serverless?

Serverless computing is a cloud computing model in which the cloud provider manages the infrastructure, automatically allocating and scaling resources as needed. Developers can focus solely on writing and deploying code, without the need to worry about server provisioning, maintenance, or scaling.

Think of it as ordering pizza without worrying about making the dough, firing up the oven, or delivering it yourself. You just ask for what you want, and it magically appears at your doorstep, hot and ready. Serverless computing is a bit like that — you focus on your code, and AWS Lambda handles the cooking and delivery behind the scenes.

Let's get started

Initially, we contemplated the idea of utilizing serverless frameworks and their enchanting plugins. NestJS, with its robust documentation, beckoned us toward this path. However, destiny had other plans in store for us.

In a plot twist worthy of a tech thriller, we decided to take a different route. Instead of relying on the magic of serverless plugins, we set our sights on the mighty AWS Serverless Application Model Command Line Interface (SAM CLI). Yes, you read that right — we chose the path of pure SAM CLI power!

The only challenge? Finding a guide that could show us the way. It felt like searching for a needle in a haystack. Fear not, for this document is here to fill that void. Together, we’ll unravel the secrets of deploying your NestJS application on AWS Lambda using the SAM CLI.

Step 1: Setup NestJS Application

Before we embark on our serverless journey, we need a NestJS application to work with. If you already have one, feel free to skip ahead, but if not, let’s create a basic NestJS app. Don’t worry; we’ll keep it simple!

  1. Prerequisites: Ensure you have Node.js and npm (Node Package Manager) installed on your machine. You can download and install them from the official website.
  2. Create a NestJS Project: Open your terminal and run the following command to create a new NestJS project:
npx @nestjs/cli new nest-lambda-app

This command will create a new NestJS project named nest-lambda-app in a directory of the same name. Feel free to choose a different name if you prefer.

3. Navigate to Your Project: Move into your newly created project directory:

cd nest-lambda-app

You can add additional controllers and services according to your project requirements (https://docs.nestjs.com/controllers)

4. Run the Application: To make sure everything is working as expected, run your NestJS app locally:

npm run start

This will start your NestJS application, and you should see an output indicating that it’s running on a specific port (usually 3000).

Access Your App: Open a web browser and navigate to http://localhost:3000. You should see the default NestJS welcome page.

Congratulations! You now have a basic NestJS application up and running. In the next steps, we’ll explore how to deploy this application as an AWS Lambda function using the SAM CLI.

Hello world :)

Step 2: Preparing Your NestJS Application for AWS Lambda

Before we can deploy our NestJS application to AWS Lambda, we need to make a few preparations:

  1. SAM CLI Installation: Ensure you have the AWS SAM CLI installed on your machine. If you haven’t already installed it, follow the instructions in the official SAM CLI documentation.
  2. Dependencies: Open your package.json file and make sure that the "@nestjs/platform-express" "aws-lambda" "aws-serverless-express" packages are installed as a dependency. If it's not, you can add it using npm or yarn.
npm install @nestjs/platform-express aws-lambda aws-serverless-express

3. Lambda-Compatible Entry File: AWS Lambda requires a specific entry file, so we’ll create one. In your project root directory, create a file named serverless.ts (or any name you prefer). This file will be the entry point for your Lambda function.

import { Handler, Context } from 'aws-lambda';
import { Server } from 'http';
import { createServer, proxy } from 'aws-serverless-express';
import { eventContext } from 'aws-serverless-express/middleware';
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import { AppModule } from './app.module';

import express from 'express';
import { ValidationPipe } from '@nestjs/common';

const binaryMimeTypes: string[] = [];

let cachedServer: Server;

async function bootstrapServer(): Promise<Server> {
if (!cachedServer) {
const expressApp = express();
const nestApp = await NestFactory.create(
AppModule,
new ExpressAdapter(expressApp),
);
nestApp.useGlobalPipes(new ValidationPipe());
nestApp.use(eventContext());
await nestApp.init();
cachedServer = createServer(expressApp, undefined, binaryMimeTypes);
}
return cachedServer;
}

export const handler: Handler = async (event: any, context: Context) => {
cachedServer = await bootstrapServer();
return proxy(cachedServer, event, context, 'PROMISE').promise;
};

This serverless.ts file, residing within the src folder serves as the entry point for our application. Within this file, we create our application instance and define the handler function, which is invoked as a Lambda function. The handler function, in turn, triggers our bootstrap function, responsible for creating and launching our NestJS application

This code is similar to your main.ts or main.js file but adapted for AWS Lambda.

4. Configuration: Create a serverless.yml file in your project root. This file will contain the configuration for your Lambda function.

AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: NestJS on AWS Lambda

Resources:
MyNestJSLambdaFunction:
Type: AWS::Serverless::Function
Properties:
Handler: dist/serverless.handler
Runtime: nodejs16.x
CodeUri: ./
MemorySize: 256
Timeout: 20
Events:
HelloWorld:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
RootPath:
Type: Api
Properties:
Path: /
Method: ANY

Outputs:
HelloWorldApi:
Description: 'API Gateway endpoint URL for the HelloWorld function'
Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/'

This serverless.yaml file serves as a crucial blueprint for deploying your NestJS application on AWS Lambda. It defines the AWS Serverless Application Model (SAM) configurations required to set up your serverless architecture. Here's a breakdown of what's happening:

Resources: In this section, we specify the AWS resources you’ll need for your deployment. The star of the show is the MyNestJSLambdaFunction, Serverless Function. This function utilizes the dist/serverless.handler as its entry point and is designed to run on Node.js 16.x. You can customize its memory size, and timeout, and it's set up to respond to an HelloWorld API Gateway event.

Outputs: The outputs section provides you with valuable information about your deployed resources. Notably, the HelloWorldApi the output reveals the API Gateway endpoint URL for your HelloWorld function.

With this serverless.yaml file in hand, you're equipped to effortlessly deploy your NestJS application as an AWS Lambda function using the SAM CLI. It's your roadmap to serverless success!"

Editing a YAML file can make you feel like a DevOps engineer :D

Developers after editing .yaml file

Step 4: Deploying Your NestJS Application with SAM CLI

Now that we have configured our serverless.yaml file, it's time to unleash the SAM CLI's magic and deploy our NestJS application to AWS Lambda. Here's how to do it:

  1. Build Your NestJS Application: Before deploying, ensure that your NestJS application is built. Run the following command in your project directory:
npm run build

Once you build the app using the above command. You will notice a dist/ folder getting generated. Inside this folder, you should observe the JavaScript files generated from your TypeScript source code. It's important to note that in the serverless.yaml file configuration, we are specifically targeting the serverless.handler function within the dist/serverless.js file. This is the entry point for your NestJS application when it's deployed as an AWS Lambda function.

After confirming the existence of the dist/ folder and its contents, you're ready to proceed with packaging and deploying your application using the SAM CLI.

2. Build Your SAM Application: Use the SAM CLI to build your serverless application:

sam build

This command will package your application and its dependencies for deployment.

when you build your application, you will also generate a .aws-sam folder. This folder contains temporary build artifacts and is used by the SAM CLI during the deployment process.

sam build

After confirming the existence of the dist/ folder, its contents, and the .aws-sam folder, you're ready to proceed with packaging and deploying your application using the SAM CLI.

Test Your API Locally: Before deploying to AWS, it’s a good practice to test your API locally to ensure everything works as expected. You can do this with the following command:

sam local start-api

You can see that our API server is working perfectly in serverless mode.

3. Deploy Your Application: Now, let’s deploy your NestJS application to AWS Lambda. Run the following command:

sam deploy --guided

You will be prompted to enter a few details, such as the deployment stage and AWS Region. Once you’ve provided these details, the deployment process will begin.

Wait for Deployment: The SAM CLI will package and deploy your application. Sit back and relax while it works its magic. Once the deployment is complete, it will provide you with information about the deployed resources.

Access Your Deployed NestJS App: The deployment process should provide you with the API Gateway endpoint URL for your NestJS application. You can use this URL to access your serverless NestJS application on AWS Lambda.

With your NestJS application successfully deployed on AWS Lambda and tested locally, you’re now enjoying the benefits of serverless computing without the complexities of server management.

The serverless approach gives perks to both developers and product owners. The first can free their mind off infrastructure concerns and focus on the core product. Product owners, in turn, spend less on running a server, and have better service scalability, faster time to market, and potential to scale.

Serverless computing offers cost efficiency for smaller workloads with its pay-as-you-go pricing, automatic scaling, and simplified deployment. However, it can introduce challenges such as cold starts, limited execution time, vendor lock-in, complex debugging, cost uncertainty for high-traffic scenarios, limited state management, resource constraints, network and storage costs, and added complexity as applications scale. These factors should be carefully considered when evaluating serverless for your specific use case.

The reality of serverless :)

“But there are still servers involved!”
– Dave R.

Thanks for reading folks. Hope it was helpful

--

--