DEV Community

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

Posted on

πŸ§™ 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! πŸ’¬

Top comments (0)