• HashiCorp Developer

  • HashiCorp Cloud Platform
  • Terraform
  • Packer
  • Consul
  • Vault
  • Boundary
  • Nomad
  • Waypoint
  • Vagrant
Terraform
  • Install
  • Tutorials
    • About the Docs
    • Configuration Language
    • Terraform CLI
    • Terraform Cloud
    • Terraform Enterprise
    • CDK for Terraform
    • Provider Use
    • Plugin Development
    • Registry Publishing
    • Integration Program
  • Registry(opens in new tab)
  • Try Cloud(opens in new tab)
  • Sign up
CDK for Terraform

Skip to main content
4 tutorials
  • Install CDK for Terraform and Run a Quick Start Demo
  • Build AWS Infrastructure with CDK for Terraform
  • Deploy Lambda Functions with TypeScript and CDK for Terraform
  • Deploy Applications with CDK for Terraform

  • Resources

  • Tutorial Library
  • Certifications
  • Community Forum
    (opens in new tab)
  • Support
    (opens in new tab)
  • GitHub
    (opens in new tab)
  • Terraform Registry
    (opens in new tab)
  1. Developer
  2. Terraform
  3. Tutorials
  4. CDK for Terraform
  5. Deploy Lambda Functions with TypeScript and CDK for Terraform

Deploy Lambda Functions with TypeScript and CDK for Terraform

  • 12min

  • TerraformTerraform

You can use the Cloud Development Kit for Terraform (CDKTF) to define advanced deployment configurations in a familiar programming language such as TypeScript, Python, or Go.

CDKTF stacks let you manage multiple Terraform configurations in the same CDKTF application. They can save you from writing repetitive CDKTF code, while allowing you to independently manage the resources in each stack. You can also use the outputs of one stack as inputs for another.

Each stack generates its own Terraform workspace so that you can manage each stack independently. You can use stacks to connect multiple deployments across your application, simplifying your infrastructure workflow. In CDKTF v0.4+, asset constructs let you manage assets for resources that need them, such as template_file, S3 bucket objects, or Lambda function archive files.

In this tutorial, you will deploy a CDKTF application made up of two stacks, each containing a simple AWS Lambda function written in TypeScript. In the process, you will use TerraformAsset to package your Lambda deployment artifact and define stacks to manage the Lambda deployments independently.

Prerequisites

The tutorial assumes that you are familiar with the CDK for Terraform workflow. If you are new to CDK for Terraform itself, refer first to the Get Started with CDK for Terraform tutorials.

For this tutorial, you will need:

  • Terraform v1.0+
  • CDK for Terraform v0.12+
  • an AWS account
  • AWS Credentials configured for use with Terraform

Terraform and CDKTF will use credentials set in your environment or through other means as described in the Terraform documentation.

Note: Some of the infrastructure in this tutorial does not qualify for the AWS free tier. Destroy the infrastructure at the end of the guide to avoid unnecessary charges. We are not responsible for any charges that you incur.

Explore CDKTF application

In your terminal, clone the sample repository.

$ git clone https://github.com/hashicorp/learn-cdktf-assets-stacks-lambda.git

Navigate to the cloned repository.

$ cd learn-cdktf-assets-stacks-lambda

This directory contains the three subdirectories.

  1. The lambda-hello-world directory hosts a Lambda handler written in TypeScript. Every Lamdba function must have a handler. When users invoke the Lambda function, it runs the handler code. This function returns "Hello world!".
  2. The lambda-hello-name directory also hosts a Lambda handler written in TypeScript. This function returns "Hello NAME!", where NAME is the value for the name query parameter. If NAME is undefined, the handler will return "Hello there!".
  3. The cdktf directory hosts the CDKTF application written in TypeScript. You will use this directory to deploy the lambda-hello-world and lambda-hello-name Lambda functions.

Notice that both Lambda functions contain pre-compiled dist directories, so you do not have to compile them in this tutorial. In addition, notice that the directories containing the Lambda handlers are not in the cdktf directory. This is best practice — you should not have application code in your infrastructure directory.

Navigate to the cdktf directory.

$ cd cdktf

Open main.ts, which contains the main CDKTF application. This application defines the LambdaStack, a CDKTF stack you will use to deploy the lambda-hello-world and lambda-hello-name functions.

This file uses the preconfigured AWS provider (@cdktf/provider-aws). Importing the library allows you to use your code editor's autocomplete functionality to help you write the CDK application code.

In the next sections, you will review the LambdaStack code and use it to deploy two different Lambda functions.

Examine the code

In this example, the LambdaStack groups all the resources necessary to deploy a Lambda function.

First the code creates a random value to ensure that the resource names for your Lambda function and IAM role are unique.

main.ts
// Create random value
const pet = new random.Pet(this, 'random-name', {
  length: 2,
})

The example code configures the AWS provider to deploy your functions to the us-west-2 region.

main.ts
new aws.AwsProvider(this, 'provider', {
  region: 'us-west-2',
})

The TerraformAsset construct helps you manage assets and expose them to your CDK resources. This code uses the TerraformAsset to package the compiled handler code into an archive and assigns it to a variable named asset.

main.ts
// Create Lambda executable
const asset = new TerraformAsset(this, 'lambda-asset', {
  path: path.resolve(__dirname, config.path),
  type: AssetType.ARCHIVE, // if left empty it infers directory and file
})

Tip: This file imports TerraformAsset and AssetType from the cdktf library.

Next the code creates an S3 bucket to host the archive containing your Lambda function and uploads it to the bucket.

main.ts
// Create unique S3 bucket that hosts Lambda executable
const bucket = new aws.S3Bucket(this, 'bucket', {
  bucketPrefix: `learn-cdktf-${name}`,
})

// Upload Lambda zip file to newly created S3 bucket
const lambdaArchive = new aws.S3BucketObject(this, 'lambda-archive', {
  bucket: bucket.bucket,
  key: `${config.version}/${asset.fileName}`,
  source: asset.path, // returns a posix path
})

Next the example code creates an IAM role for your Lambda function and the function itself. Notice that the IAM role references the lambdaRolePolicy object defined at the beginning of the file. The stack also grants the Lambda role access to write to CloudWatch.

main.ts
// Create Lambda role
const role = new aws.IamRole(this, 'lambda-exec', {
  name: `learn-cdktf-${name}-${pet.id}`,
  assumeRolePolicy: JSON.stringify(lambdaRolePolicy),
})

// Add execution role for lambda to write to CloudWatch logs
new aws.IamRolePolicyAttachment(this, 'lambda-managed-policy', {
  policyArn:
    'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole',
  role: role.name,
})

// Create Lambda function
const lambdaFunc = new aws.LambdaFunction(this, 'learn-cdktf-lambda', {
  functionName: `learn-cdktf-${name}-${pet.id}`,
  s3Bucket: bucket.bucket,
  s3Key: lambdaArchive.key,
  handler: config.handler,
  runtime: config.runtime,
  role: role.arn,
})

Then the code creates an API gateway that targets your Lambda function. This will make your function accessible via an HTTPS endpoint. The LambdaPermission gives your API gateway endpoint permission to invoke your Lambda function.

main.ts
// Create and configure API gateway
const api = new aws.Apigatewayv2Api(this, 'api-gw', {
  name: name,
  protocolType: 'HTTP',
  target: lambdaFunc.arn,
})

new aws.LambdaPermission(this, 'apigw-lambda', {
  functionName: lambdaFunc.functionName,
  action: 'lambda:InvokeFunction',
  principal: 'apigateway.amazonaws.com',
  sourceArn: `${api.executionArn}/*/*`,
})

Inspect function definitions

Toward the bottom of the main.ts file, you will find definitions for the lambda-hello-world and lambda-hello-name functions using LambdaStack.

main.ts
new LambdaStack(app, 'lambda-hello-world', {
  path: '../lambda-hello-world/dist',
  handler: 'index.handler',
  runtime: 'nodejs10.x',
  stageName: 'hello-world',
  version: 'v0.0.1',
})

new LambdaStack(app, 'lambda-hello-name', {
  path: '../lambda-hello-name/dist',
  handler: 'index.handler',
  runtime: 'nodejs10.x',
  stageName: 'hello-name',
  version: 'v0.0.1',
})

Notice how each definition maps to the respective function's properties: the lambda-hello-world's path points to ../lambda-hello-world/dist and its stageName points to hello-world. Once you have created the LambdaStack class, you can use it to deploy as many similarly configured Lambda functions as you want.

View application stacks

Install the dependencies for the CDKTF application.

$ npm install
added 305 packages, and audited 357 packages in 5s

35 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

When you create a new CDKTF application from scratch, the cdktf init command will install these dependencies. The application from the sample repository is already initialized, so you can use npm install to install the application's dependencies.

Now, run cdktf provider to install the random and aws providers. This configuration uses the random provider to ensure the IAM role name is unique.

$ cdktf provider add "aws@~>4.0" random
Checking whether pre-built provider exists for the following constraints:
  provider: aws
  version : ~>4.0
  language: typescript
  cdktf   : 0.12.0

Found pre-built provider.
Adding package @cdktf/provider-aws @ 9.0.0
Installing package @cdktf/provider-aws @ 9.0.0 using npm.
Package installed.
Checking whether pre-built provider exists for the following constraints:
  provider: random
  version : latest
  language: typescript
  cdktf   : 0.12.0

Found pre-built provider.
Adding package @cdktf/provider-random @ 2.0.0
Installing package @cdktf/provider-random @ 2.0.0 using npm.
Package installed.

List all the stacks defined in your CDKTF application. Notice these map to the new LambdaStack definitions declared in main.ts.

$ cdktf list
Stack name                      Path
lambda-hello-world              cdktf.out/stacks/lambda-hello-world
lambda-hello-name               cdktf.out/stacks/lambda-hello-name

Deploy Hello World function

Deploy the lambda-hello-world stack. Remember to confirm the deploy by choosing Approve.

$ cdktf deploy lambda-hello-world
lambda-hello-world  Initializing the backend...
lambda-hello-world
                    Successfully configured the backend "local"! Terraform will automatically
                    use this backend unless the backend configuration changes.
lambda-hello-world  Initializing provider plugins...
lambda-hello-world  - Finding hashicorp/aws versions matching "4.23.0"...
lambda-hello-world  - Finding hashicorp/random versions matching "3.3.2"...
lambda-hello-world  - Using hashicorp/aws v4.23.0 from the shared cache directory
lambda-hello-world  - Installing hashicorp/random v3.3.2...
lambda-hello-world  - Installed hashicorp/random v3.3.2 (signed by HashiCorp)
##...
                    Plan: 8 to add, 0 to change, 0 to destroy.

                    Changes to Outputs:
                    + url = (known after apply)

                    ─────────────────────────────────────────────────────────────────────────────

                    Saved the plan to: plan

                    To perform exactly these actions, run the following command to apply:
                    terraform apply "plan"

Please review the diff output above for lambda-hello-world
❯ Approve  Applies the changes outlined in the plan.
  Dismiss
  Stop
##...
                    Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

                    Outputs:


lambda-hello-world  url = "https://bur6dfzia5.execute-api.us-west-2.amazonaws.com"

  lambda-hello-world
  url = https://bur6dfzia5.execute-api.us-west-2.amazonaws.com

Open the url output in your web browser to confirm the API gateway returns "Hello world!".

Deploy Hello Name function

Deploy the lambda-hello-name stack. Remember to confirm the deploy with Approve.

$ cdktf deploy lambda-hello-name
lambda-hello-name  Initializing the backend...
lambda-hello-name
                   Successfully configured the backend "local"! Terraform will automatically
                   use this backend unless the backend configuration changes.
lambda-hello-name  Initializing provider plugins...
lambda-hello-name  - Finding hashicorp/aws versions matching "4.23.0"...
lambda-hello-name  - Finding hashicorp/random versions matching "3.3.2"...
lambda-hello-name  - Using hashicorp/aws v4.23.0 from the shared cache directory
lambda-hello-name  - Using hashicorp/random v3.3.2 from the shared cache directory
##...
                   Plan: 8 to add, 0 to change, 0 to destroy.

                   Changes to Outputs:
                   + url = (known after apply)

                   ─────────────────────────────────────────────────────────────────────────────

                   Saved the plan to: plan

                   To perform exactly these actions, run the following command to apply:
                   terraform apply "plan"

Please review the diff output above for lambda-hello-name
❯ Approve  Applies the changes outlined in the plan.
  Dismiss
  Stop
##...
                   Apply complete! Resources: 8 added, 0 changed, 0 destroyed.

                   Outputs:


lambda-hello-name  url = "https://oogzjki3cb.execute-api.us-west-2.amazonaws.com"

  lambda-hello-name
  url = https://oogzjki3cb.execute-api.us-west-2.amazonaws.com

Open the url output in your web browser to confirm the API gateway returns "Hello there!".

Append ?name=Terry to the URL. The API gateway will respond with "Hello Terry!".

Inspect synthesized stacks

CDKTF stacks have their own configuration and state files.

In your cdktf directory, find the cdktf.out directory. CDKTF generates this directory when it synthesizes the Terraform configuration from the application code when you run cdktf synth or cdktf deploy.

Notice how there are two directories in cdktf.out/stacks. Each directory corresponds with the stack defined in the application code and contains the generated Terraform configuration, plan file, and assets.

cdktf.out/
├── manifest.json
└── stacks
    ├── lambda-hello-name
    │   ├── assets
    │   │   └── lambda-asset
    │   │       └── ACDAAB9A40AD1E0EC3B40C4B53527E85
    │   │           └── archive.zip
    │   ├── cdk.tf.json
    │   └── plan
    └── lambda-hello-world
        ├── assets
        │   └── lambda-asset
        │       └── BD42BA06A24B006B4907A4F399734ACC
        │           └── archive.zip
        ├── cdk.tf.json
        └── plan

In addition, you will find terraform.lambda-hello-name.tfstate and terraform.lambda-hello-name.tfstate in your cdktf directory. The cdktf deploy STACK_NAME generates a state file named terraform.STACK_NAME.tfstate where STACK_NAME is the stack name. Like any Terraform state file, you should not commit these files into source control.

Clean up resources

Destroy the infrastructure you created in this tutorial.

First, destroy the lambda-hello-world stack. Remember to confirm the destroy with Approve.

$ cdktf destroy lambda-hello-world
lambda-hello-world  Initializing the backend...
lambda-hello-world  Initializing provider plugins...
                    - Reusing previous version of hashicorp/aws from the dependency lock file
lambda-hello-world  - Reusing previous version of hashicorp/random from the dependency lock file
lambda-hello-world  - Using previously-installed hashicorp/aws v4.23.0
lambda-hello-world  - Using previously-installed hashicorp/random v3.3.2
##...
                    Plan: 0 to add, 0 to change, 8 to destroy.

                    Changes to Outputs:
                    - url = "https://bur6dfzia5.execute-api.us-west-2.amazonaws.com" -> null

                    ─────────────────────────────────────────────────────────────────────────────

                    Saved the plan to: plan

                    To perform exactly these actions, run the following command to apply:
                    terraform apply "plan"

Please review the diff output above for lambda-hello-world
❯ Approve  Applies the changes outlined in the plan.
  Dismiss
  Stop
##..
lambda-hello-world  aws_s3_object.lambda-archive (lambda-archive): Destruction complete after 0s
lambda-hello-world  aws_s3_bucket.bucket (bucket): Destroying... [id=learn-cdktf-lambda-hello-world20220727201212716200000001]
lambda-hello-world  aws_s3_bucket.bucket (bucket): Destruction complete after 0s
lambda-hello-world
                    Destroy complete! Resources: 8 destroyed.

Now, destroy the lambda-hello-name stack. Remember to confirm the destroy with Approve.

$ cdktf destroy lambda-hello-name
lambda-hello-name  Initializing the backend...
lambda-hello-name  Initializing provider plugins...
                   - Reusing previous version of hashicorp/random from the dependency lock file
lambda-hello-name  - Reusing previous version of hashicorp/aws from the dependency lock file
lambda-hello-name  - Using previously-installed hashicorp/random v3.3.2
lambda-hello-name  - Using previously-installed hashicorp/aws v4.23.0
##..
                    Plan: 0 to add, 0 to change, 8 to destroy.

                    Changes to Outputs:
                   - url = "https://oogzjki3cb.execute-api.us-west-2.amazonaws.com" -> null

                    ─────────────────────────────────────────────────────────────────────────────

                    Saved the plan to: plan

                    To perform exactly these actions, run the following command to apply:
                    terraform apply "plan"

Please review the diff output above for lambda-hello-world
❯ Approve  Applies the changes outlined in the plan.
  Dismiss
  Stop
##...
lambda-hello-name  aws_s3_object.lambda-archive (lambda-archive): Destruction complete after 1s
lambda-hello-name  aws_s3_bucket.bucket (bucket): Destroying... [id=learn-cdktf-lambda-hello-name20220727201429435300000001]
lambda-hello-name  aws_s3_bucket.bucket (bucket): Destruction complete after 0s
lambda-hello-name
                   Destroy complete! Resources: 8 destroyed.

Next steps

In this tutorial, you deployed and destroyed two different Lambda functions using CDKTF. In the process, you learned how to use TerraformAsset to package your Lambda deployment artifact and stacks to independently manage the Lambda deployments.

You can also connect multiple stacks together to define multiple deployments in a single CDKTF application.

For more information on topics covered in this tutorial, check out the following resources.

  • Inspect the code for a fully integrated approach in fully-integrated branch. This approach uses yarn based monorepo setup and introduces a NodejsFunction Construct which bundles the code transparently via esbuild. Visit this PR includes additional context and instructions.
  • Read more about constructs in the CDKTF Constructs documentation.
  • Read more about assets in the CDKTF Assets documentation.
  • Read more about CDKTF releases.
 Previous
 Next

This tutorial also appears in:

  •  
    8 tutorials
    HashiConf Announcements - Terraform 1.0
    Try the features you heard about at HashiConf including CDKTF Golang support, and the Terraform Cloud private module registry. Version Terraform, state, providers, and Terraform Cloud.
    • Terraform

On this page

  1. Deploy Lambda Functions with TypeScript and CDK for Terraform
  2. Prerequisites
  3. Explore CDKTF application
  4. View application stacks
  5. Deploy Hello World function
  6. Deploy Hello Name function
  7. Inspect synthesized stacks
  8. Clean up resources
  9. Next steps
Give Feedback(opens in new tab)
  • Certifications
  • System Status
  • Terms of Use
  • Security
  • Privacy
  • Trademark Policy
  • Trade Controls
  • Give Feedback(opens in new tab)