Prepare NestJS for Deployment

Setup build script

Make sure your package.json file has a build script defined or the deployments will fail. For most applications, the build script should be nest build. If your application has pre-build or post-build steps, you can define them in the build script around the nest build.

Setup INestApplication creation

How NestJS is deployed in a lambda function is different from how it is deployed in an ECS container. To ensure that the same code base can be deployed in both architectures, we need to decouple creating the INestApplication from standing up the server. This is done by defining a createApplication function that can be called in the lambda handler or in the ECS container. Zonké looks for the createApplication function in src/bootstrap.ts. Here is an example of a simple bootstrap function:

Sample bootstrap.ts file

src/bootstrap.ts
import { INestApplication } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';

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

export async function createApplication(): Promise<INestApplication> {
  const app = await NestFactory.create(AppModule, {
    cors: {
      credentials: true,
      methods: ['GET', 'POST'],
      optionsSuccessStatus: 200,
      origin: [process.env.ALLOWED_ORIGIN!], // The environment variable is passed in by Zonké at deployment time.
    },
  });

  return app.setGlobalPrefix('api');
}

Zonké Internal - How the Lambda handler is defined

Example handler.ts file

src/handler.ts
import serverlessExpress from '@codegenie/serverless-express';
import { Callback, Context, Handler } from 'aws-lambda';

import { createApplication } from '@/bootstrap';


let server: Handler;

const bootstrap = async () => {
  const app = await createApplication();
  await app.init();

  return serverlessExpress({ 
    app: app.getHttpAdapter().getInstance(),
  });
};

export const handler: Handler = async (
  event: any,
  context: Context,
  callback: Callback,
) => {
  server = server ?? (await bootstrap());

  return server(event, context, callback);
};

Zonké Internal - How the ECS server is defined

Example main.ts file

src/main.ts
import { createApplication } from '@/bootstrap';

async function bootstrap() {
  const app = await createApplication();

  // NOTE: The port is passed in by Zonké as a public environment variable to the ECS container.
  await app.listen(process.env.PORT!);
}

bootstrap();