Terraform to AWS CDK Converter (Python)

Rewrite Terraform HCL as an AWS CDK v2 stack in Python, with aws_cdk constructs, snake_case keyword arguments and the Python idioms your team already uses.

Your codeTerraform (HCL)
Drop the file to load it
Tab indents · Esc, Tab exits
ResultAWS CDK (Python)
Your AWS CDK (Python) will appear hereClick Convert to CDK or press Ctrl Enter
stack.py
Don't paste secrets

How to convert Terraform to AWS CDK in Python

To convert Terraform to AWS CDK in Python, paste your HCL into the editor above and press Convert to CDK. You get a Stack subclass where each resource is a construct created with self as its scope. Save it as stack.py in an app made with cdk init app --language python, then run cdk synth.

  1. Paste your TerraformPaste HCL into the Terraform (HCL) editor, or open a .tf or .hcl file up to 500 KB. Related resources, such as a queue and its dead-letter queue, convert best in the same paste.
  2. Check for secretsBefore anything is sent, the page looks for AWS keys, private keys and tokens in your code and shows you where they are, so you can swap in placeholders.
  3. Convert to CDKPress Convert to CDK or Ctrl + Enter. The Python stack streams in as it's written, and Stop ends the conversion early.
  4. Save stack.pyRead through the output, search for TODO: comments, then Download it as stack.py or Copy it into your project.
  5. Wire it into app.py and synthImport the class in app.py, instantiate it with your env, and run cdk synth in the activated virtual environment. A wrong keyword argument fails here, before anything is deployed.
Four steps to run converted Terraform as AWS CDK Python: cdk init app with Python, install aws-cdk-lib in the virtual environment, add stack.py to app.py, then run cdk synth and cdk diff
Where the converted stack.py fits in a new CDK Python project.

Why rewrite Terraform as a Python CDK app

Python teams move to CDK so infrastructure lives in the same language as their Lambda handlers, data pipelines and tests. A CDK app can import your own modules, loop over a config dictionary, and be unit tested with pytest and aws_cdk.assertions, which is hard to match with HCL.

The translation isn't mechanical, though. Terraform nests settings in blocks, while CDK Python takes keyword arguments and small property classes: a redrive_policy written with jsonencode() becomes dead_letter_queue=sqs.DeadLetterQueue(...). The converter does that restructuring for a whole module at once, so you start from a stack that already reads like Python.

It helps most when you're retiring a handful of Terraform modules, splitting a monorepo, or showing a team what their existing infrastructure looks like as CDK. For TypeScript projects, use the Terraform to CDK TypeScript converter.

Terraform arguments mapped to CDK Python keyword arguments: visibility_timeout_seconds to Duration.seconds, redrive_policy to sqs.DeadLetterQueue, an ARN reference to dlq.queue_arn, and billing_mode to dynamodb.BillingMode
HCL arguments become typed keyword arguments and helper objects.

From HCL blocks to Python constructs

In a Python CDK app, each Terraform resource becomes a construct instantiated with self as its scope, for example sqs.Queue(self, "Orders", visibility_timeout=Duration.seconds(60)). Attribute references like aws_sqs_queue.orders_dlq.arn become Python attributes such as dlq.queue_arn, and time values use Duration instead of plain seconds.

CDK is written in TypeScript and published to Python through jsii, so the classes are identical and only the naming changes: visibilityTimeout is visibility_timeout, and enums keep their upper-case members. Because CDK synthesizes to CloudFormation, the deployed resources can differ slightly from Terraform's. AWS's guide to working with CDK in Python covers setup and conventions.

The converted code manages new resources. It doesn't take over the ones Terraform already created. Use cdk import for resources you want to keep, and run cdk diff before every deploy.

Four steps to move Terraform-managed resources into a CDK Python stack: cdk import, terraform state rm or a removed block, delete the moved .tf blocks, then confirm cdk diff shows no changes
For resources that already exist, adopt them into CloudFormation before Terraform lets go.

Terraform to CDK Python: quick reference

Common HCL patterns and the Python they should become.

Terraform HCL patterns and their AWS CDK Python equivalents
PatternTerraform HCLCDK Python
Resourceresource "aws_sns_topic" "alerts"sns.Topic(self, "Alerts")
Attribute referenceaws_sns_topic.alerts.arnalerts.topic_arn
Seconds and daysvisibility_timeout_seconds = 60visibility_timeout=Duration.seconds(60)
String enumsbilling_mode = "PAY_PER_REQUEST"billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST
Nested blockattribute { name = "pk" type = "S" }dynamodb.Attribute(name="pk", type=dynamodb.AttributeType.STRING)
for_each over a mapfor_each = var.topicsA dict comprehension or for key, value in topics.items()
Variablevariable "stage" {}A constructor argument, or self.node.try_get_context("stage")
Outputoutput "arn" { value = … }CfnOutput(self, "Arn", value=…)
Lambda module name(not applicable)from aws_cdk import aws_lambda as lambda_, because lambda is a Python keyword

Key features

  • Pythonic outputKeyword arguments in snake_case, Duration helpers and enum members instead of raw strings and numbers.
  • Nested blocks become property classesBlocks such as attribute, lifecycle_rule or a redrive policy turn into classes like dynamodb.Attribute and sqs.DeadLetterQueue.
  • for_each and count become Python loopsRepeated resources are written as loops or dict comprehensions over plain Python data.
  • A ready-to-use Stack classThe output is a Stack subclass with the standard __init__(self, scope, construct_id, **kwargs) signature, ready to import in app.py.
  • Gaps marked with TODOAnything without a CDK equivalent, such as ignore_changes, is called out in a TODO: comment rather than guessed.
  • Names and comments keptYour resource names and comments carry over, so reviewers can match each construct to the HCL it came from.
  • Secret check, then streamingKeys and tokens are caught in the browser first, and the stack streams in with a Stop button.

Examples: Terraform converted to CDK Python

Two examples of HCL that changes shape in Python. Choose Try this example to load the Terraform into the converter. Your output may use different construct IDs or formatting.

An S3 bucket with encryption and a lifecycle rule

Since AWS provider v4, encryption and lifecycle rules are separate Terraform resources. In CDK they're keyword arguments on the bucket: sse_algorithm = "aws:kms" without a key maps to BucketEncryption.KMS_MANAGED.

Terraform (HCL)
resource "aws_s3_bucket" "logs" {
  bucket = "acme-app-logs"
}

resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
  bucket = aws_s3_bucket.logs.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "aws:kms"
    }
  }
}

resource "aws_s3_bucket_lifecycle_configuration" "logs" {
  bucket = aws_s3_bucket.logs.id
  rule {
    id     = "expire-old-logs"
    status = "Enabled"
    filter {}
    expiration {
      days = 90
    }
  }
}
AWS CDK (Python)
from aws_cdk import Stack, Duration, aws_s3 as s3
from constructs import Construct


class LogsStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        s3.Bucket(
            self,
            "Logs",
            bucket_name="acme-app-logs",
            encryption=s3.BucketEncryption.KMS_MANAGED,
            lifecycle_rules=[
                s3.LifecycleRule(
                    id="expire-old-logs",
                    expiration=Duration.days(90),
                )
            ],
        )

for_each over a map of topics

A for_each map becomes a Python dictionary, and the resources are created in a dict comprehension. Keeping them in self.topics lets other constructs look them up by key, just like aws_sns_topic.events["orders"].

Terraform (HCL)
variable "topics" {
  type = map(string)
  default = {
    orders   = "Order events"
    invoices = "Invoice events"
  }
}

resource "aws_sns_topic" "events" {
  for_each     = var.topics
  name         = "${each.key}-events"
  display_name = each.value
}
AWS CDK (Python)
from aws_cdk import Stack, aws_sns as sns
from constructs import Construct

TOPICS = {
    "orders": "Order events",
    "invoices": "Invoice events",
}


class EventsStack(Stack):
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        self.topics = {
            key: sns.Topic(
                self,
                f"{key.capitalize()}Events",
                topic_name=f"{key}-events",
                display_name=label,
            )
            for key, label in TOPICS.items()
        }

Tips for better results

  • Paste related resources together. A queue and its dead-letter queue, or a table and the function that reads its stream, convert into cleaner references in one paste.
  • Leave names out where you can. An explicit queue_name="orders" stops CloudFormation from replacing the resource without deleting it first. Keep fixed names only for resources you'll import.
  • Pin the library. Put an exact aws-cdk-lib version in requirements.txt so every machine and CI job synthesizes the same template.
  • Test the stack. aws_cdk.assertions.Template.from_stack() lets you assert, in pytest, that the converted stack still has the properties your Terraform set.
  • Run cdk synth early. jsii checks keyword arguments at synth time, so a misspelled property fails in seconds, before anything is deployed.

Common mistakes to avoid

  • Importing aws_lambda as lambda. lambda is a reserved word in Python. Use aws_lambda as lambda_, as the converter does.
  • Passing plain numbers for durations. Props like visibility_timeout and timeout expect Duration.seconds(60), not 60.
  • Shadowing id. Name the constructor argument construct_id, as cdk init does, so it doesn't hide Python's built-in id().
  • Forgetting the virtual environment. Running cdk synth outside the activated .venv picks up a different or missing aws-cdk-lib and fails with import errors.
  • Releasing Terraform state first. If you run terraform state rm before cdk import succeeds, nothing manages the resource for a while. Adopt it in CDK first, then release it from Terraform.

Frequently asked questions

How do I convert Terraform to AWS CDK Python?

Paste your HCL into the converter above and press Convert to CDK. You get a Python Stack class with one construct per resource. Save it as stack.py in an app created with cdk init app --language python, add it to app.py, and run cdk synth in the virtual environment.

Does converting Terraform to CDK move my existing resources?

No. The converter changes code, not infrastructure. Existing resources stay in Terraform state. To manage them from CDK, adopt them with cdk import or CloudFormation resource import, then remove them from Terraform with terraform state rm. For the trade-offs, see AWS CDK vs Terraform for existing AWS stacks.

Why does the Python code use snake_case?

The CDK is written in TypeScript and published to Python through jsii, which translates property names to Python conventions. visibilityTimeout in TypeScript is visibility_timeout in Python. The classes are the same.

Which version of AWS CDK does the output use?

CDK v2. Constructs come from the single aws-cdk-lib package (imported as aws_cdk) and Construct from constructs. CDK v1, which used a separate pip package per service such as aws-cdk.aws-s3, reached end-of-support on June 1, 2023.

How do I pass Terraform variables into the CDK app?

Common options are constructor arguments on your stack class, context values in cdk.json read with try_get_context, or environment variables read in app.py. The converter usually turns variables with defaults into arguments or constants you can adjust.

Can I test the converted stack?

Yes. CDK's aws_cdk.assertions module works with pytest: synthesize the stack with Template.from_stack() and assert resource properties, such as a queue's visibility timeout or a table's billing mode.

Should I choose Python or TypeScript for CDK?

Pick the language your team maintains. Both use the same constructs. TypeScript is CDK's native language, so if that's your stack, use the TypeScript version of this converter.

Is my Terraform or CDK code stored?

No. The code is sent to an AI model hosted on NVIDIA's API only to produce the conversion, and ChatWithCloud doesn't store or log it. Your latest draft stays in your browser. Before converting, replace account IDs you consider sensitive, and any secrets in variable defaults, with placeholders. For the full picture, see whether it's safe to paste AWS code into an AI converter.

Is it free, and how much can I paste?

Yes. Each conversion takes up to 60,000 characters, and you can open files up to 500 KB. Without an account you get 6 conversions a minute and 60 a day. A free account raises that to 12 a minute and 200 a day and lists your recent conversions on your dashboard. The guide to ChatWithCloud free converter limits shows how far they stretch for a real migration.

Related tools and next steps