Write TypeScript Lambda functions in AWS CDK - Complete Guide

avatar

Borislav Hadzhiev

Wed Apr 21 20214 min read

Updated on Wed Apr 21 2021

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 infrastructure using TypeScript, so it makes sense to also write the Lambda code using TypeScript.

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

In order to write a Lambda function in TypeScript and provision it in 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

First, we will define the infrastructure for our function, using CDK:

lib/cdk-starter-stack.ts
import * as lambda from '@aws-cdk/aws-lambda'; import {NodejsFunction} from '@aws-cdk/aws-lambda-nodejs'; import * as cdk from '@aws-cdk/core'; 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`), }); } }

Let's go over the code:

  • We have a simple 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 have 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 have passed to the NodejsFunction constructor are the same props the generic Function constructor supports.

Writing the Code for TypeScript Lambdas #

Our function code will be very simple, in order to avoid any unnecessary distractions.

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, }; }

In the code snippet, we have defined a simple lambda function, where 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 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 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'], }, });

We've provided the minify and externalModules options for the bundling, prop:

  • 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 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 go 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, have our dependencies break every 2-3 months and waste hours and hours debugging.

Cleanup #

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

shell
npx 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 #

Add me on LinkedIn

I'm a Web Developer with TypeScript, React.js, Node.js and AWS experience.

Let's connect on LinkedIn

Join my newsletter

I'll send you 1 email a week with links to all of the articles I've written that week

Buy Me A Coffee