Write TypeScript Lambda functions in AWS CDK - Complete Guide

avatar

Borislav Hadzhiev

Tue Apr 12 20224 min read

Updated - Tue Apr 12 2022

Table of Contents #

  1. Writing the Infrastructure for TypeScript Lambdas in AWS CDK
  2. Writing the Code for TypeScript Lambdas
  3. Deploying TypeScript Lambdas with AWS CDK
  4. Optimizing TypeScript Lambdas with CDK
  5. Discussion

Writing the Infrastructure for TypeScript Lambdas in AWS CDK #

We write our CDK code using TypeScript, so it makes sense to also write our Lambda code in TypeScript.

Nodejs doesn't natively support TypeScript, so we have to first compile our TypeScript code to JavaScript before we can deploy our Lambda functions.

In order to write a Lambda function in TypeScript and provision it with CDK, we have to use the NodejsFunction construct, which uses esbuild to automatically transpile and bundle our code.

The code for this article is available on GitHub

Let's define the infrastructure for our function using CDK:

lib/cdk-starter-stack.ts
import * as cdk from 'aws-cdk-lib'; import {NodejsFunction} from 'aws-cdk-lib/aws-lambda-nodejs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import * as path from 'path'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const myFunction = new NodejsFunction(this, 'my-function', { memorySize: 1024, timeout: cdk.Duration.seconds(5), runtime: lambda.Runtime.NODEJS_14_X, handler: 'main', entry: path.join(__dirname, `/../src/my-lambda/index.ts`), }); } }
If you still use CDK version 1, switch to the cdk-v1 branch in the GitHub repository.

Let's go over the code:

  • We have a CDK stack that provisions a single Lambda function

  • The Lambda function uses the NodejsFunction construct, which automatically transpiles and bundles our code, regardless if it's written in JavaScript or TypeScript

  • The entry prop we passed to the function constructor is a path to the lambda function's code on the local file system. The entry prop supports files with .js, .jsx, .ts and .tsx extensions.

  • The other props we passed to the NodejsFunction constructor are the same props the generic Function construct supports.

Writing the Code for TypeScript Lambdas #

In order to avoid unnecessary distractions, our function code will be very simple.

src/my-lambda/index.ts
import {APIGatewayProxyEventV2, APIGatewayProxyResultV2} from 'aws-lambda'; export async function main( event: APIGatewayProxyEventV2, ): Promise<APIGatewayProxyResultV2> { console.log('event 👉', event); return { body: JSON.stringify({message: 'Successful lambda invocation'}), statusCode: 200, }; }

We defined a simple lambda function, in which we've typed the event and the response.

Deploying TypeScript Lambdas with AWS CDK #

Our CDK code gets compiled down to CloudFormation before a deployment.

When we synthesize our CloudFormation stack, it gets generated in the cdk.out directory. This is also where the asset files for our Lambda functions are stored.

Let's run the synth command to generate the lambda assets:

shell
npx aws-cdk synth

If we now take a look at the assets folder in the cdk.out directory, we can see that our Lambda function's code has been compiled down to JavaScript.

cdk out lambda

At this point we are ready to deploy our stack:

shell
npx aws-cdk deploy

Now that the Lambda function has been successfully deployed, we can run a quick test using the Lambda console:

lambda invoked

At this point we've successfully invoked a Lambda function that we wrote using TypeScript and provisioned via AWS CDK.

Optimizing TypeScript Lambdas with CDK #

The NodejsFunction construct uses esbuild under the hood to automatically transpile and bundle our code.

We can use the construct to write JavaScript or TypeScript and everything just works automatically. There are no webpack configuration files we have to manage.

We can reduce the bundle size of our Lambda functions by setting the minify property to true in the props object of the NodejsFunction:

lib/cdk-starter-stack.ts
const myFunction = new NodejsFunction(this, 'my-function', { // ...rest // 👇 bundling: { minify: true, externalModules: ['aws-sdk'], }, });
The code for this article is available on GitHub

We've set the minify and externalModules options on the bundling, property:

  • minify is a boolean that allows us to specify whether we want to minify the code of our Lambda function. This enables us to decrease bundle size and improve performance for larger functions.

  • externalModules is a string array that allows us to specify which modules should NOT be bundled with our Lambda code. This enables us to exclude modules that are already available in the Lambda runtime - for instance aws-sdk and layers.

    For example, if you used an npm package called yup as a Lambda layer, you would add the string yup to the externalModules array because layers are already available in the Lambda environment.

I'll now run the synth command to inspect the output:

shell
npx aws-cdk synth

If I open the cdk.out directory and look at the lambda asset, we can see that it has been minified and is a one-liner:

lambda minified

Discussion #

The esbuild library is written in Golang and is way faster than any other bundler I've ever used, so deployments for medium sized projects go relatively quick. Look at the speed comparison to other bundlers.

The best thing about this approach is that we don't have to manage webpack configurations and have our dependencies break every 2-3 months.

Cleanup #

To delete the stack from your account, run the destroy command:

shell
npx aws-cdk destroy

Outro #

We managed to use ESBuild to write Lambda functions in Typescript. Now all of our code, including the infrastructure, is written using the same language.

The code for this article is available on GitHub

Further Reading #

Use the search field on my Home Page to filter through my more than 1,000 articles.