What if you could write your infrastructure in TypeScript, the way you would with the AWS CDK, but have Terraform deploy it instead of CloudFormation? That’s exactly what CDK for Terraform offers, and in this post I’ll show you why the combination is worth a look and then build a small serverless REST API with it from start to finish.
There are plenty of IaC tools, but two come up all the time in AWS projects. On AWS, CloudFormation is the native deployment engine, and the AWS CDK sits on top of it. Terraform is the popular alternative that works across clouds. Each has clear strengths and weaknesses.
Terraform, from HashiCorp, describes infrastructure in its own declarative language, HCL (HashiCorp Configuration Language). It isn’t tied to one cloud: the same tool and workflow can manage AWS, Azure, Google Cloud Platform and many others through providers. On AWS specifically, Terraform deployments also tend to finish faster than the equivalent CloudFormation stack updates.
AWS CDK (Cloud Development Kit) is an open-source framework that lets you describe cloud resources in general-purpose languages such as TypeScript. It doesn’t deploy anything itself. Instead, it synthesises your code into ordinary CloudFormation templates, and CloudFormation creates the resources. The benefit of this extra layer is that a high-level construct can expand a few lines of code into a very long template, so developers can write and maintain infrastructure in a language they already know.
Here’s how they compare side by side:
| Terraform (HCL) | AWS CDK | |
|---|---|---|
| Authoring language | HCL, a domain-specific language | TypeScript, Python, Java, C#, Go |
| Deployment engine | Terraform | CloudFormation |
| Cloud coverage | Multi-cloud via providers | AWS-focused |
| Abstraction | Modules | Reusable, high-level constructs |
| Typical deployment speed on AWS | Faster | Slower |
The weaknesses of each tool are mostly the other tool’s strengths:
The bridge between them is CDK for Terraform (CDKTF). You write constructs in a familiar language, CDKTF synthesises them into Terraform configuration, and Terraform provisions the resources.
Our target is a minimal REST API: one GET /hello endpoint on API Gateway, backed by a Lambda function that returns a hello-world response.
Before you start, install:
Start with an empty directory for the code:

Then initialise a CDKTF project in it, choosing TypeScript as the language:

The generated main.ts already contains a CDKTF app and a single stack. Everything we build goes inside that stack.
Since AWS is our target, the first thing to set up is the Terraform AWS provider. I also want Terraform’s state stored remotely in an S3 bucket rather than on my laptop, so deployments can be tracked reliably. Both are just constructs (AwsProvider and S3Backend) in the stack:

The provider gets the target region and the AWS account ID to deploy into. The backend gets the bucket name and the related state settings.
The function needs an IAM role it can assume, with the permissions of the basic Lambda execution role attached:

The handler lives in src/index.ts. Since this is a hello-world app, all it does is return a fixed greeting:

Next, we tell the stack about that code and create the Lambda resource:

This creates an S3 bucket for the function’s code package, uploads the code and creates the function, using the role from the previous step as its execution role.
With the function in place, we can expose it through an API Gateway REST API:

There are four pieces here: the REST API itself, a /hello resource, a GET method on that resource, and a proxy integration that sends requests to our Lambda function.
An API isn’t reachable until it has been deployed to a stage, so we add a deployment and a stage, giving the stage a name and linking it to the API:

It’s easy to forget this last step. Even with the integration defined, API Gateway can’t invoke the function until the function’s resource-based policy allows it. The LambdaPermission construct adds that permission for our API:

That completes the infrastructure code.
You can browse the complete project in this GitHub repository.
Check that your AWS credentials are configured so Terraform can reach your account. Then build the project and deploy it:

CDKTF installs any missing packages, synthesises the Terraform configuration and runs the deployment. When it finishes, call the endpoint to confirm everything works:

One thing you’ll notice straight away is how fast the deployment is compared with pushing a similar stack through CloudFormation. That speed makes a real difference when you iterate many times a day.
When you’re done, cdktf destroy removes every resource the project created.
S3Backend stores state in a bucket you name, but it doesn’t create that bucket. Create it (ideally with versioning enabled) before your first deploy.LambdaPermission source ARN. If the source ARN doesn’t match your API, you’ll get a “permission denied” style error from API Gateway even though the integration looks correct.@cdktf/provider-aws). Constructs from the AWS CDK’s aws-cdk-lib can’t be used directly, so expect to write some things at a lower level than you would in the AWS CDK.Good fit: teams that already use Terraform but want to write infrastructure in a real programming language, teams that like the CDK approach but want faster deployments or resources outside AWS, and projects that share TypeScript between application and infrastructure code.
Think twice: if your team is happy with plain HCL and modules, CDKTF adds a synthesis step and another toolchain to maintain. If you rely heavily on the AWS CDK’s high-level L2/L3 constructs, you’ll miss them. And before committing to it long term, check the current support status of CDKTF on HashiCorp’s site.
Combining CDK-style development with Terraform gives you a strong workflow for cloud infrastructure. You define resources in a language like TypeScript, which keeps the code readable and maintainable, and you get Terraform’s cloud-agnostic reach and faster deployments. The result is flexible, modular and convenient for developers, and it makes provisioning infrastructure faster and more dependable day to day.