DEV Community

Cover image for πŸ§™ Lambdalith Mastery: Elevating NestJS Deployment on AWS Lambda with CDK & Webpack
Valentin BEGGI for AWS Community Builders

Posted on

2

πŸ§™ Lambdalith Mastery: Elevating NestJS Deployment on AWS Lambda with CDK & Webpack

TL;DR πŸ“š

  • Why is a Lambdalith approach a high ROI choice for many? πŸ’Έ
  • Learn how to deploy a monolithic NestJS app on AWS Lambda using Webpack and AWS CDK. πŸš€

The Lambdalith Edge for NestJS on AWS Lambda 🌟

🧠 A Lambdalith is a monolithic architecture approach for serverless applications where a single AWS Lambda function serves the entire API, rather than deploying separate functions for each endpoint.

Opt for a Lambdalith and reap multiple benefits for your NestJS API:

  • Faster Rollouts: Quicker deployments and streamlined management, irrespective of your number of routes.
  • Minimized Cold Starts: Enhanced performance through more frequent reuse of a single Lambda function.
  • Easier Logging: A single point for logs simplifies monitoring and alert setup.
  • Full NestJS Benefits: Fully exploit NestJS's rich features and community support.

While a Lambdalith might mean lengthier cold starts and broader control scopes, its efficiency, simplicity, and high return on investment are unmatched.

Monorepo structure πŸš§πŸ“¦: I strongly advice you embrace a monorepo structure, with a package for your API and a package for your infrastructure (CDK).

Setting Up the Infrastructure with AWS CDK πŸ—οΈ

AWS CDK transforms infrastructure into code. Kick things off by installing AWS CDK and initiating a TypeScript project with cdk init app --language typescript.

In the lib/my-stack.ts file, begin with the core of your setup: the Lambda function.

// LambdaNestStack in stack.ts
const apiNestHandlerFunction = new Function(this, "ApiNestHandler", {
  code: Code.fromAsset("api/dist"), // πŸ‘ˆ This is crucial
  runtime: Runtime.NODEJS_18_X,
  handler: "main.handler",
  environment: {}, // πŸ‘ˆ You might need env variables
});
Enter fullscreen mode Exit fullscreen mode

Next up, create a Rest API with a Lambda proxy at its root. This API Gateway acts as the traffic controller, directing all requests to your Lambda-powered NestJS app. All route paths will be directed to your single Lambda. πŸ—Ύ

const api = new RestApi(this, "Api", {
    deploy: true,
    defaultMethodOptions: {
    apiKeyRequired: true,
    },
});

api.root.addProxy({
    defaultIntegration: new LambdaIntegration(apiNestHandlerFunction, { proxy: true }),
});

const apiKey = api.addApiKey("ApiKey"); // πŸ‘ˆ to ease your testing

const usagePlan = api.addUsagePlan("UsagePlan", {
    name: "UsagePlan",
    apiStages: [
    {
        api,
        stage: api.deploymentStage,
    },
    ],
});

usagePlan.addApiKey(apiKey);
Enter fullscreen mode Exit fullscreen mode

In this snippet, Code.fromAsset("api/dist") is crucial. It points to the location of our bundled NestJS app, ensuring efficient Lambda execution.

Prepping the NestJS App for Lambda 🦁

Start by creating a new NestJS app with nest new api. Then, install the @nestjs/platform-express and @vendia/serverless-express packages.
You now have a classic NestJS app, ready to be adapted for AWS Lambda.

Next to the main.ts file, create a new lambda.ts file. This file will be the entry point of our Lambda function.

// lambda.ts
import { NestFactory } from '@nestjs/core';
import { ExpressAdapter } from '@nestjs/platform-express';
import serverlessExpress from '@vendia/serverless-express';
import { Context, Handler } from 'aws-lambda';
import express from 'express';

import { AppModule } from './app.module';

let cachedServer: Handler;

async function bootstrap() {
  if (!cachedServer) {
    const expressApp = express();
    const nestApp = await NestFactory.create(
      AppModule,
      new ExpressAdapter(expressApp),
    );

    nestApp.enableCors();

    await nestApp.init();

    cachedServer = serverlessExpress({ app: expressApp });
  }

  return cachedServer;
}

const handler = async (event: any, context: Context, callback: any) => {
  const server = await bootstrap();
  return server(event, context, callback);
};

module.exports.handler = handler;
Enter fullscreen mode Exit fullscreen mode

This code will be executed by AWS Lambda. It creates a NestJS app and adapts it to the AWS Lambda environment. It also ensures that the NestJS app is only created once, improving performance. ⚑

πŸ—’οΈ Side Note: You could easily setup a single main.ts entry point by leveraging env variables to deduce the execution context: Lambda or local

Now, we need to bundle this TypeScript code into a single file...πŸ€“

Packing it Up with Webpack πŸ“¦πŸ§™β€β™‚οΈ

There are several ways to bundle a NestJS app for AWS Lambda. You could use Lambda Layers, but this is not the most efficient approach. Instead, we'll use Webpack to bundle our NestJS app into a single file, which we'll then deploy with AWS CDK.

Let's start by creating a new webpack.config.js file in our API package. This file will define our Webpack configuration.

module.exports = function (options, webpack) {
  return {
    ...options,
    entry: ['./src/lambda.ts'],
    externals: [],
    output: {
      ...options.output,
      libraryTarget: 'commonjs2',
    },
    plugins: [
      ...options.plugins,
      new webpack.IgnorePlugin({
        checkResource(resource) {
          // Ignoring non-essential modules for Lambda deployment
          return lazyImports.includes(resource);
        },
      }),
    ],
  };
};
Enter fullscreen mode Exit fullscreen mode

This configuration bundles our Lambda entry file (lambda.ts) and its dependencies, creating a lean and efficient package for AWS Lambda!

Make sure to create a build-lambda script in your package.json file!

{
  "scripts": {
    "build-lambda": "nest build --webpack --webpackPath webpack.config.js"
  }
}
Enter fullscreen mode Exit fullscreen mode

Deploying the NestJS App: To the Cloud! ☁️

Your NestJS app is now a compact bundle, thanks to Webpack. Deploying? It's as simple as:

  • Build: Run npm run build-lambda in your API package.
  • Deploy: In your infrastructure package, execute cdk deploy.

And like that, your NestJS app ascends to AWS Lambda, primed for action. πŸ’«

Your High-Performance NestJS App now lives on AWS πŸš€

Congratulations! You've unlocked the strategy for a potent, scalable, and efficient NestJS app on AWS Lambda, all packaged neatly with Webpack and AWS CDK. πŸ‘πŸ‘

Please feel free to comment if anything was unclear or if you found a better way to achieve this result! πŸ’¬

Image of Timescale

πŸš€ pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applicationsβ€”without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more β†’

Top comments (0)

Retry later
πŸ‘‹ Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay