Last updated: Jan 27, 2024
Reading timeยท4 min
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.
Let's define the infrastructure for our function using CDK.
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_18_X, handler: 'main', entry: path.join(__dirname, `/../src/my-lambda/index.ts`), }); } }
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.
In order to avoid unnecessary distractions, our function code will be very simple.
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.
Our CDK code gets compiled down to CloudFormation before a deployment.
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.
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.
At this point, we are ready to deploy our stack.
npx aws-cdk deploy
Now that the Lambda function has been successfully deployed, we can run a quick test using the Lambda console.
At this point, we've successfully invoked a Lambda function that we wrote using TypeScript and provisioned via AWS CDK.
The
NodejsFunction
construct uses esbuild
under the hood to automatically transpile and bundle
our code.
We can reduce the bundle size of our Lambda functions by setting the minify
property to true
in the props
object of the NodejsFunction
.
const myFunction = new NodejsFunction(this, 'my-function', { // ...rest // ๐ bundling: { minify: true, externalModules: ['aws-sdk'], }, });
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.
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.
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.
To delete the stack from your account, run the
destroy
command.
npx aws-cdk destroy
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.
I've also written an article on how to provision lambda functions in CDK without using TypeScript.
You can learn more about the related topics by checking out the following tutorials: