💸 Catch expensive AWS mistakes before deployment! See cost impact in GitHub PRs for Terraform & CDK. Join the Free Beta!
AWS CDK vs Terraform: The Complete 2026 Comparison

AWS CDK vs Terraform: The Complete 2026 Comparison

Written on January 2nd, 2026 by Danny Steenman

Last updated: January 2nd, 2026

26 min read
0 views
--- likes

You're about to make a decision that will shape your infrastructure code for the next 3-5 years. Unlike most technology choices, picking between AWS CDK and Terraform means committing to a specific workflow, mental model, and ecosystem. Switching later means rewriting everything.

Here's the uncomfortable truth: the infrastructure-as-code landscape changed significantly in 2025. HashiCorp deprecated CDKTF (the "best of both worlds" option) and moved Terraform to a Business Source License. Meanwhile, AWS CDK continues to evolve with new features like CDK Migrate.

These changes matter for your decision in ways that existing comparisons don't address.

By the end of this guide, you'll understand not just which tool to choose, but why you're choosing it, what trade-offs you're accepting, and how to change your mind later if needed.

Executive Summary: Which Tool Should You Choose?

Let me give you the direct answer before we dive into the details.

Quick Recommendation Matrix

Choose AWS CDK if:

  • Your infrastructure is 100% AWS
  • Your team are developers who love TypeScript, Python, Java, C#, or Go
  • You want sensible defaults and high-level abstractions
  • You don't need multi-cloud support (now or in the foreseeable future)

Choose Terraform if:

  • You need multi-cloud support (AWS, Azure, GCP)
  • You prefer declarative configuration over programming
  • You have existing Terraform expertise and modules
  • Your ops team (not developers) manages infrastructure

Consider both if: You have complex use cases where CDK handles application infrastructure and Terraform manages foundational or multi-cloud resources. This adds complexity, so only do it if you have specific reasons.

TL;DR: Key Takeaways

  1. Neither is "better" - they're optimized for different scenarios
  2. CDK = AWS-native programming with CloudFormation underneath
  3. Terraform = Multi-cloud declarative with manual state management
  4. Migration is possible but non-trivial (plan for lock-in)
  5. CDKTF is deprecated - don't count on "best of both worlds"

If you need more depth to validate this recommendation, the comparison table below shows the key technical differences.

The Quick Comparison Table

Here's a side-by-side view of the major differences:

FeatureAWS CDKTerraform
LanguagesTypeScript, Python, Java, C#, Go, JavaScriptHCL (HashiCorp Configuration Language)
Cloud SupportAWS onlyMulti-cloud (3,000+ providers)
State ManagementAutomatic via CloudFormationManual configuration (S3 backend recommended)
Deployment EngineCloudFormationTerraform engine
RollbackAutomatic on failureManual intervention required
TestingBuilt-in assertions moduleThird-party tools (Terratest, etc.)
Setup RequiredBootstrap per account/regionBackend configuration per project
AbstractionsL1, L2, L3 constructsFlat module structure
Learning Curve (Devs)Low (familiar languages)Medium (learn HCL)
Learning Curve (Ops)Medium (requires programming)Low (declarative config)
LicensingApache 2.0 (open source)Business Source License (BSL)

Why these differences matter: The fundamental distinction is that CDK generates CloudFormation templates and leverages AWS's deployment engine, while Terraform manages its own state and deployment. This architectural difference affects everything from rollback behavior to how you debug issues.

Understanding the Fundamentals

Before comparing these tools, you need to understand what they actually do under the hood. Both are Infrastructure as Code tools, but they approach the problem from different angles.

What is AWS CDK?

AWS CDK (Cloud Development Kit) is an open-source framework that lets you define cloud infrastructure using familiar programming languages. Your CDK code is synthesized into CloudFormation templates, which are then deployed to provision resources.

Key characteristics:

  • Supports six languages: TypeScript, JavaScript, Python, Java, C#, and Go
  • Synthesizes to CloudFormation: CDK isn't a replacement for CloudFormation - it's a layer on top
  • Three levels of constructs for different abstraction needs
  • Deployment via CloudFormation: Inherits CloudFormation's benefits (automatic rollback, change sets) and limitations (quotas, behaviors)

The construct model is the heart of CDK:

  • L1 (CFN Resources): Direct 1:1 mapping to CloudFormation resources (e.g., CfnBucket). No abstraction, complete control
  • L2 (Curated Constructs): Opinionated resources with sensible defaults and best practices built in (e.g., s3.Bucket). Most commonly used
  • L3 (Patterns): Multi-resource architectures that create complete solutions (e.g., ApplicationLoadBalancedFargateService creates ECS Fargate + ALB with one construct)

If you want to dive deeper into CDK fundamentals, check out my beginner's guide to AWS CDK.

What is Terraform?

Terraform is a platform-agnostic IaC tool using HashiCorp Configuration Language (HCL). It manages infrastructure through its own deployment engine and state files, supporting multiple cloud providers and services.

Key characteristics:

  • Uses HCL: A declarative configuration language designed to be human-readable
  • Platform-agnostic: Supports AWS, Azure, GCP, and 3,000+ other providers through plugins
  • State files: JSON files that track your deployed infrastructure (critical for knowing what exists)
  • Own deployment engine: Terraform handles deployments directly, not through CloudFormation

The Terraform workflow is straightforward:

  1. terraform init - Initialize working directory, download providers
  2. terraform plan - Preview what changes will be applied
  3. terraform apply - Provision or update infrastructure
  4. terraform destroy - Remove all managed infrastructure

The Imperative vs Declarative Paradigm

Here's the fundamental difference in how you think about infrastructure:

CDK is imperative - you write code that describes HOW to create infrastructure using programming logic (loops, conditionals, functions). You have full programming capabilities at your disposal.

Terraform is declarative - you write configuration that describes WHAT infrastructure should exist, not how to create it. The tool figures out how to get there.

Let me show you the difference with a simple S3 bucket:

// CDK (TypeScript) - imperative approach
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cdk from 'aws-cdk-lib';

const bucket = new s3.Bucket(this, 'MyBucket', {
  encryption: s3.BucketEncryption.S3_MANAGED,
  versioned: true,
  removalPolicy: cdk.RemovalPolicy.RETAIN
});
# Terraform (HCL) - declarative approach
resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-unique-bucket-name"
}

resource "aws_s3_bucket_versioning" "my_bucket" {
  bucket = aws_s3_bucket.my_bucket.id
  versioning_configuration {
    status = "Enabled"
  }
}

resource "aws_s3_bucket_server_side_encryption_configuration" "my_bucket" {
  bucket = aws_s3_bucket.my_bucket.id
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

Notice how CDK's L2 construct handles encryption and versioning with simple properties, while Terraform requires separate resource blocks. This is the abstraction benefit of CDK's constructs - but it also means less explicit visibility into what's being created.

Neither paradigm is superior. They serve different mental models and team skillsets.

The CDKTF Deprecation: What It Means for Your Decision

Before we go deeper into the comparison, you need to understand a significant recent change that affects your decision.

What Was CDKTF?

CDK for Terraform (CDKTF) was HashiCorp's attempt to combine CDK's programming language benefits with Terraform's multi-cloud capabilities. Built on the JSII library, it enabled writing Terraform configurations in C#, Python, TypeScript, Java, or Go.

The workflow was: define infrastructure using CDK constructs, CDKTF generates Terraform HCL configurations, then deploy using standard Terraform workflows.

It promised the best of both worlds: familiar programming languages with Terraform's multi-cloud provider ecosystem.

Why HashiCorp Deprecated It

HashiCorp deprecated CDKTF in December 2025. The likely reasons include:

  • Maintenance burden of keeping two abstraction layers in sync
  • Limited adoption compared to native Terraform
  • Complexity that didn't justify the benefits
  • Strategic focus on the core Terraform product

Existing CDKTF projects can continue but won't receive updates or new features.

Implications for Tool Selection Today

Don't choose CDKTF - it's deprecated and won't evolve.

The "best of both worlds" doesn't exist anymore. You have to choose between CDK (AWS-only) or Terraform (multi-cloud).

This validates the binary choice we're discussing: if HashiCorp couldn't make the synthesis approach work well, hybrid approaches are likely complex.

If you absolutely need programming languages plus multi-cloud support, consider Pulumi as an alternative (though that's outside this comparison's scope).

The Licensing Question: Terraform's BSL and What It Means

The second recent change affecting Terraform is the licensing shift.

Terraform's License Change Explained

Terraform moved from Mozilla Public License (open source) to Business Source License (BSL). This is not a minor change.

BSL restricts commercial use in certain scenarios, specifically around creating competing products. The license automatically converts to open source after a specified time period.

AWS documentation notes: "Terraform changed from Mozilla Public License (open source) to Business Source License (BSL). This affects commercial use and forking rights. Organizations should review licensing implications."

Practical Implications for Your Organization

For most users: No change. You can still use Terraform freely for infrastructure management.

For enterprises: Review with your legal team if you're a cloud provider or building competing IaC products.

For open-source advocates: The loss of pure open-source licensing may be a philosophical concern.

Future uncertainty: HashiCorp could change license terms again.

The Fundamental Business Model Problem

Here's a perspective that often gets overlooked in technical comparisons.

AWS's position: AWS doesn't need to monetize CloudFormation or CDK directly. They make money when you run resources on AWS. CDK exists to help you deploy infrastructure faster, safer, and more automated - which means more AWS consumption.

AWS's aligned incentives: The better CDK is, the more AWS resources you'll deploy. Their business model aligns with your success.

HashiCorp's dilemma: No cloud infrastructure revenue means they must monetize the tooling itself. This is why Terraform Cloud exists and why the license changed.

Why the license changed: Other companies (Spacelift, env0, Scalr) were building commercial products on top of open-source Terraform, threatening HashiCorp's revenue.

Strategic risk: When your IaC vendor's survival depends on monetizing the tool, future changes may not align with your interests. AWS will continue investing in CDK because it drives their core business. This stability doesn't exist for Terraform.

This isn't a technical limitation - it's a business risk factor for long-term infrastructure decisions.

OpenTofu as an Alternative

OpenTofu is a Terraform fork created in response to the BSL change:

  • Maintains Mozilla Public License (true open source)
  • Aims for Terraform compatibility
  • Supported by Linux Foundation
  • Trade-off: Smaller ecosystem, less mature than Terraform

Consider OpenTofu if open-source licensing is critical to your organization, but be aware of the ecosystem maturity trade-offs.

Core Differences That Matter

Now let's get into the technical differences that affect your day-to-day work.

Language and Syntax

CDK: Use your preferred programming language with full IDE support. You get autocomplete, type checking, refactoring, and all the tooling you're used to. TypeScript is the most popular choice, but Python, Java, C#, and Go are all first-class citizens.

Terraform: Learn HCL, a declarative language designed specifically for infrastructure. It's relatively simple but requires learning new syntax. IDE support exists through plugins but isn't as rich as general-purpose language tooling.

CDK advantage: Leverage existing language skills, strong typing prevents configuration errors at compile time.

Terraform advantage: HCL is easier for non-developers to read and learn. A declarative config file is more approachable than imperative code for many ops teams.

Multi-Cloud vs AWS-Native Focus

Terraform's superpower: 3,000+ providers enable multi-cloud (AWS, Azure, GCP) and SaaS integration (GitHub, Datadog, Kubernetes, etc.). If you need to manage anything beyond AWS, Terraform likely has a provider.

CDK's focus: Deep AWS integration with no multi-cloud support. You cannot deploy Azure or GCP resources with CDK.

When multi-cloud matters: Hybrid cloud architectures, avoiding vendor lock-in, managing non-AWS resources alongside AWS.

When multi-cloud doesn't matter: Committed to AWS, leveraging AWS-specific features, no plans for multi-cloud.

AWS feature availability: CDK gets new AWS features when CloudFormation supports them (usually within a week). Terraform's AWS provider may lag by weeks or months for new features.

Abstraction Levels: Constructs vs Modules

CDK's three-level constructs:

  • L1: Direct CloudFormation resources (CfnBucket), no abstraction, complete control
  • L2: Curated resources with sensible defaults (s3.Bucket), most commonly used
  • L3: Multi-resource patterns (ApplicationLoadBalancedFargateService), create complex architectures with minimal code

Terraform's modules: Flat structure, reusable containers for multiple resources. The Terraform Registry has thousands of community-vetted modules.

CDK advantage: L2/L3 constructs dramatically reduce boilerplate. Creating ECS Fargate with an ALB is 10+ resources in Terraform but one L3 construct in CDK.

Terraform advantage: Mature module ecosystem with years of community refinement. More explicit about what resources are being created.

For deep dives into CDK constructs, see my posts on understanding CDK constructs and CDK stacks.

Learning Curve Reality Check

For developers: CDK is easier. You use familiar programming languages, existing tooling, and patterns you already know. Learning HCL is an extra cognitive load.

For ops teams: Terraform is easier. Declarative configuration is more approachable than learning to program. The mental model (describe what you want) is simpler than imperative code (describe how to get it).

For mixed teams: Terraform's HCL serves as a neutral middle ground that both developers and ops can work with.

CDK hidden complexity: You still need to understand CloudFormation behavior underneath. When debugging fails, you'll be reading CloudFormation error messages and understanding its state model.

Terraform hidden complexity: State management and HCL limitations take time to master. You'll learn the quirks of the state file the hard way.

Honest assessment: Neither is "easy." They're different skill investments with different learning paths.

State Management Philosophy

State management is where these tools diverge most fundamentally.

CDK's CloudFormation-Managed State

CDK doesn't manage state directly - CloudFormation does it automatically.

How it works: When you deploy a CDK stack, CloudFormation tracks the state of all resources in that stack. This state is stored in the CloudFormation service itself, not in a file you manage.

Advantages:

  • Zero state management overhead
  • Automatic locking (no concurrent deployment conflicts)
  • No security configuration needed for state storage
  • State visible via CloudFormation console or API

Limitations:

  • Tied to CloudFormation quotas and constraints (e.g., 500 resources per stack)
  • Less control over state operations
  • Can't easily inspect or manipulate state directly

Terraform's Manual State Configuration

Terraform requires explicit state backend configuration.

How it works: Terraform stores state in JSON files (typically terraform.tfstate). By default this is local, but for team environments you configure a remote backend (typically S3).

Recommended AWS setup:

  • S3 bucket with versioning enabled (state storage)
  • S3 server-side encryption (SSE-KMS recommended)
  • IAM policies restricting access
  • DynamoDB table for state locking (being deprecated in future versions)
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}

Advantages:

  • Full control over state storage, versioning, and backup
  • Works with any cloud provider
  • Can inspect and manipulate state when needed

Challenges:

  • Must configure encryption, access controls, and locking manually
  • State file security is your responsibility
  • Team coordination around state requires discipline

Security Implications of Each Approach

Terraform state security concerns:

  • State files contain sensitive data (passwords, keys, connection strings) in plain text
  • Must enable S3 encryption (SSE-KMS recommended)
  • Must restrict IAM access to state bucket
  • Best practice: Use AWS Secrets Manager for sensitive values, not hardcoded in Terraform

AWS prescriptive guidance recommends: "Immediately rotate secrets after Terraform ingestion" because they persist in state.

CDK state security:

  • Managed by AWS CloudFormation service
  • No file-level security configuration needed
  • Still visible in CloudFormation console to authorized IAM users
  • Secrets should be referenced from Secrets Manager at runtime, not synthesis time

Bottom line: Terraform's state file exposure is higher risk. You need to be more deliberate about state security with Terraform.

Setup and Prerequisites

What do you need to do before deploying anything?

CDK Bootstrap Requirements

CDK requires a one-time bootstrapping process per AWS account/region combination.

What bootstrapping creates:

  • S3 bucket for storing Lambda code and assets (naming: cdk-hnb659fds-assets-ACCOUNT-REGION)
  • ECR repository for Docker images
  • IAM roles for permissions (CloudFormation, asset publishing, lookups)

Command: cdk bootstrap

Permissions needed: cloudformation:*, ecr:*, ssm:*, s3:*, iam:*

The bootstrap stack (CDKToolkit) is deployed as a CloudFormation stack and is safe to run multiple times - it upgrades if necessary.

For a detailed walkthrough, see my guide on AWS CDK bootstrapping.

If you want to skip the manual setup and start with a production-ready foundation, check out my AWS CDK Starter Kit. It includes secure OIDC authentication, automated CI/CD with GitHub Actions, and branch-based deployments - all the boilerplate I found myself copy-pasting across client projects, refined into a single starting point. See the documentation for setup instructions.

Terraform Backend Setup

Terraform has no automatic bootstrapping - you configure the backend yourself.

Recommended setup for AWS:

  • Create S3 bucket with versioning enabled
  • Enable S3 server-side encryption
  • Create IAM policies restricting access
  • Optionally create DynamoDB table for state locking

Key difference: You must create these resources manually or with separate Terraform/CloudFormation before you can use them as your backend. It's a chicken-and-egg problem that teams typically solve with a small bootstrap script.

Granularity: You decide whether to use one state file per project, per environment, or some other scheme.

Comparison summary:

  • CDK: One command, automatic resource creation, required per account/region
  • Terraform: Manual resource setup, flexible configuration, per-project choice

If you want to skip the manual backend configuration and start with a production-ready setup, check out my AWS Terraform Starter Kit. It includes secure OIDC authentication, automated CI/CD with GitHub Actions, and security scanning built in - the same boilerplate I refined across multiple client projects. See the documentation for setup instructions.

Deployment Workflow Comparison

What does your daily deployment experience look like?

CDK: Synth to Deploy to Rollback

The CDK deployment workflow follows these steps:

  1. Synthesis: cdk synth converts your CDK code to CloudFormation templates (the "cloud assembly")
  2. Preview: cdk diff shows what will change compared to the deployed stack
  3. Deploy: cdk deploy synthesizes fresh templates, uploads assets to S3/ECR, creates/updates CloudFormation stack
  4. Rollback: CloudFormation automatically rolls back on deployment failure

Asset handling:

  • Lambda code is zipped and uploaded to the S3 staging bucket
  • Docker images are built locally and pushed to the ECR repository
  • CloudFormation references these assets during deployment
# Preview changes
cdk diff

# Deploy a specific stack
cdk deploy MyStack

# Deploy all stacks
cdk deploy "*"

Key benefit: Automatic rollback means failed deployments don't leave your infrastructure in a broken state.

Terraform: Init to Plan to Apply

The Terraform workflow is explicit about each step:

  1. Initialize: terraform init downloads providers and initializes the backend
  2. Plan: terraform plan shows what changes will be made (compares state with desired config)
  3. Apply: terraform apply provisions or updates infrastructure, updates state file
  4. Destroy: terraform destroy removes all managed infrastructure
# Initialize (first time or when providers change)
terraform init

# Preview changes
terraform plan

# Apply changes
terraform apply

# Tear down everything
terraform destroy

No automatic rollback: If a deployment fails partway through, you must manually fix or destroy/recreate. This is a significant operational difference from CDK.

Previewing Changes: cdk diff vs terraform plan

Both tools let you preview changes before deployment - this is critical for production safety.

cdk diff:

  • Compares current code with deployed CloudFormation stack
  • Shows resource additions, modifications, deletions
  • Displays property-level before/after values

terraform plan:

  • Compares desired state (code) with current state (state file)
  • Shows proposed changes with +/- indicators
  • More detailed output showing attribute-level changes

Key difference: CDK diff queries the live CloudFormation stack; Terraform plan uses the state file. If someone modified infrastructure outside Terraform, the state file might be stale.

Recommendation: Always run preview before deploying to production. Make it a mandatory CI/CD gate.

Testing Your Infrastructure Code

Quality assurance for infrastructure is just as important as application code.

CDK's Built-in Testing Framework

CDK includes native testing support through the aws-cdk-lib/assertions module.

Two testing approaches:

Fine-grained assertions (recommended for most cases):

  • Test specific resource properties
  • Clear test failures indicating exact problems
  • Stable across CDK version upgrades
import { Template } from 'aws-cdk-lib/assertions';

const template = Template.fromStack(stack);

// Verify Lambda function configuration
template.hasResourceProperties('AWS::Lambda::Function', {
  Runtime: 'nodejs18.x',
  Handler: 'index.handler',
  MemorySize: 256
});

Snapshot tests:

  • Compare entire synthesized template against a baseline
  • Useful for catching unintended changes during refactoring
  • Can break due to CDK upgrades or metadata changes

Compatible test frameworks: Jest (TypeScript/JavaScript), Pytest (Python), JUnit (Java), NUnit/xUnit (.NET)

Workflow: Synthesize stack, run assertions to verify template, integrate into CI/CD pipeline.

Terraform's Third-Party Testing Ecosystem

Terraform has no native testing framework - you must use third-party tools.

Popular options:

  • Terratest (Go-based): Deploys real infrastructure, runs tests, tears down
  • terraform-compliance: Policy-as-code testing using BDD syntax
  • tflint: Linter for Terraform code
  • terraform validate: Built-in syntax validation (not comprehensive testing)

Trade-off: More flexible but requires additional tool learning and integration.

Testing complexity: Often requires actually deploying infrastructure to test (unlike CDK's template assertions). This makes tests slower and more expensive.

Which Approach Fits Your CI/CD Pipeline?

CDK advantage: Testing integrates seamlessly with existing application test frameworks. Add infrastructure tests to the same pipeline as application code.

CDK workflow: Run npm test or pytest, fail the build on test failures, same as application code.

Terraform challenge: Requires separate testing tools and potentially separate CI stages.

Terraform benefit: Can test against actual deployed infrastructure (more realistic but slower and more expensive).

Recommendation: If your team already has a strong testing culture, CDK's built-in support reduces friction significantly.

Security and Compliance Comparison

Will your security team approve this tool, and how do you enforce compliance?

Security Scanning Tools

CDK security tools:

  • cdk-nag: Checks CDK constructs against AWS best practices and compliance standards (HIPAA, PCI-DSS, etc.)
  • CloudFormation Guard: Policy-as-code validation for synthesized templates
  • CDK Aspects: Custom validation logic that runs during synthesis

Terraform security tools:

  • tfsec: Static analysis for Terraform code
  • Checkov: Multi-cloud policy-as-code scanner (works with both CDK and Terraform)
  • Terraform Sentinel: HashiCorp's policy-as-code framework (requires Terraform Enterprise/Cloud)
  • OPA (Open Policy Agent): Flexible policy engine

Maturity: Terraform's security tooling ecosystem is more mature with more options.

Policy-as-Code Capabilities

CDK Aspects: TypeScript/Python code that validates constructs during synthesis.

Example use case: Enforce S3 bucket encryption across all buckets. The Aspect runs before CloudFormation deployment and fails the build on violations.

Terraform Sentinel/OPA: Policy languages for validating Terraform plans. Can prevent non-compliant infrastructure from being deployed.

Comparison: Terraform's policy-as-code ecosystem is more established for enterprise compliance. If you need sophisticated policy enforcement with governance workflows, Terraform has more mature options.

Secret Management Approaches

Best practice for both tools: Use AWS Secrets Manager or Parameter Store, never hardcode secrets.

CDK approach:

// Reference existing secret at runtime
const secret = secretsmanager.Secret.fromSecretNameV2(
  this, 'MySecret', 'my-secret-name'
);

Secrets are retrieved at runtime, not synthesis time. Never hardcode in CDK code.

Terraform approach:

data "aws_secretsmanager_secret_version" "my_secret" {
  secret_id = "my-secret-name"
}

Critical: Secrets appear in the state file in plain text. You must protect the state file with encryption and access controls. AWS recommends rotating secrets immediately after Terraform ingestion.

Security concern: Terraform's state file exposure is higher risk than CDK for sensitive data.

Drift Detection and Remediation

CloudFormation drift detection (CDK):

  • Detects when resources are modified outside CloudFormation
  • Available via console or API
  • Shows which properties drifted
  • Cannot auto-remediate (must redeploy stack)

Terraform drift detection:

  • terraform plan compares state file with actual infrastructure
  • Shows what would change to bring infrastructure back to desired state
  • terraform apply remediates drift
  • More integrated into normal workflow

Advantage Terraform: Drift detection is core to the plan/apply workflow, making it natural to catch and fix.

Both require: Regular drift detection runs to catch manual changes.

Honest Pros and Cons

Let's be direct about the real trade-offs you're accepting.

AWS CDK Advantages and Limitations

Advantages:

  1. Programming language support - TypeScript, Python, Java, C#, Go, JavaScript with full IDE features
  2. High-level abstractions - L2/L3 constructs reduce boilerplate dramatically
  3. Automatic state management - CloudFormation handles state with zero configuration
  4. Built-in testing - Native unit and snapshot testing support
  5. AWS integration - First-class support, gets new features when CloudFormation does
  6. Best practices built-in - L2/L3 constructs encode AWS recommended configurations
  7. Rapid development - Create complex architectures with minimal code
  8. CloudFormation benefits - Automatic rollback, change sets, drift detection
  9. Reusable constructs - Share components via npm, PyPI, Maven, NuGet
  10. Type safety - Compile-time checking prevents configuration errors

Limitations:

  1. Bootstrapping required - One-time setup per AWS account/region with multiple resources
  2. AWS-only - Cannot deploy to other cloud providers or SaaS platforms
  3. CloudFormation dependency - Limited by CloudFormation capabilities, quotas (500 resources/stack), and behaviors
  4. Learning curve for ops - Requires programming knowledge, steeper for traditional ops teams
  5. Newer ecosystem - Less mature than Terraform's 9+ year ecosystem
  6. Construct availability - Not all AWS features have L2/L3 constructs yet (fall back to L1/CFN)

Terraform Advantages and Limitations

Advantages:

  1. Multi-cloud support - 3,000+ providers for AWS, Azure, GCP, and diverse services
  2. Platform agnostic - No cloud vendor lock-in, consistent tooling across providers
  3. Mature ecosystem - Extensive modules, tools, and community (9+ years)
  4. No bootstrapping - No upfront environment setup required
  5. Declarative syntax - HCL easier for teams with diverse skillsets to learn
  6. Drift detection - Built-in drift detection core to the workflow
  7. Code reusability - Terraform Registry with thousands of vetted modules
  8. Broad adoption - Industry standard with extensive documentation and resources
  9. Agentless - No software installation on managed infrastructure
  10. Modular architecture - DRY principle through modules and composition

Limitations:

  1. Manual state management - Requires S3 bucket, encryption, IAM, and locking configuration
  2. State file security risk - Contains sensitive data in plain text requiring careful protection
  3. No automatic rollback - Manual intervention required for failed deployments
  4. Feature lag - New AWS features may take time to appear in AWS provider
  5. Limited testing - No native testing framework, requires third-party tools
  6. Licensing change - Business Source License instead of open source
  7. Business model risk - HashiCorp must monetize the tool itself, creating potential for future restrictive changes
  8. State locking complexity - Requires additional setup (DynamoDB being deprecated)
  9. HCL learning curve - New language to learn for developers used to general-purpose languages

Real-World Experiences

What problems will you actually face?

Common Gotchas and Pain Points

CDK Gotchas:

  1. CloudFormation stack updates can fail mid-deployment - manual intervention required via console
  2. Construct configuration sometimes synthesizes to unexpected CloudFormation - use cdk synth to verify
  3. Cross-stack references require stacks in same environment - common error for beginners
  4. Bootstrap version mismatches cause cryptic errors - keep bootstrap updated
  5. L1 constructs require CloudFormation property knowledge - no abstraction benefit

For help with cross-stack errors, see my guide on cross-stack references in CDK.

Terraform Gotchas:

  1. State file corruption from concurrent modifications - locking is critical
  2. Sensitive data in state file - must secure state bucket rigorously
  3. Provider version changes can break existing code - pin versions
  4. terraform plan doesn't catch all errors - some only appear during apply
  5. New AWS features lag - may wait weeks or months for provider updates

When the Pros Become Cons

CDK Examples:

  • "Programming flexibility" becomes "too much magic" when debugging synthesized CloudFormation
  • "High-level abstractions" become "I can't customize this" when L2/L3 constructs don't match your exact needs
  • "Automatic state management" becomes "I can't debug state issues" when CloudFormation behaves unexpectedly
  • "AWS-native integration" becomes "I'm locked into AWS" when business strategy shifts to multi-cloud

Terraform Examples:

  • "Declarative simplicity" becomes "I can't express this logic" when you need complex conditional resource creation
  • "Multi-cloud support" becomes "lowest common denominator" when AWS-specific features aren't available
  • "Mature ecosystem" becomes "outdated modules" when community modules don't keep up with best practices
  • "Manual state control" becomes "state file nightmare" when team grows and state conflicts increase

Decision Framework

Based on your specific situation, which tool should you choose?

Choose CDK If...

Definitive scenarios:

  1. Your infrastructure is 100% AWS with no multi-cloud requirements (now or in foreseeable future)
  2. Your team are developers who prefer TypeScript, Python, Java, C#, or Go over learning HCL
  3. You value rapid development and want to leverage L2/L3 constructs to reduce boilerplate
  4. Testing is critical and you want native testing framework integration
  5. You're building AWS-native applications (serverless, containers) where CDK constructs shine
  6. You have strong governance requirements and want to distribute custom constructs with enforced standards

Team profiles that benefit:

  • Application developers managing their own infrastructure
  • Startups committed to AWS ecosystem
  • Organizations with TypeScript/Python expertise
  • Teams practicing test-driven infrastructure development

Choose Terraform If...

Definitive scenarios:

  1. You need multi-cloud or hybrid-cloud (AWS + Azure/GCP/on-premises)
  2. You manage non-AWS resources (GitHub, Datadog, Kubernetes, etc.) alongside AWS
  3. You want to avoid vendor lock-in as a strategic principle
  4. Your team are ops-focused and prefer declarative configuration over programming
  5. You have existing Terraform expertise and modules already built
  6. Drift detection is critical to your operational workflow

Team profiles that benefit:

  • DevOps/SRE teams managing infrastructure
  • Enterprises with multi-cloud strategy
  • Organizations with existing Terraform investment
  • Teams preferring declarative over imperative approaches

Team Composition Matters

  • Developer-heavy teams - CDK (leverage programming skills)
  • Ops-heavy teams - Terraform (declarative, easier to learn)
  • Mixed teams - Terraform (HCL is neutral middle ground)

Question to ask: "Who will actually write and maintain this code daily?"

Consider: Training 10 ops engineers to program vs training 10 developers to learn HCL. Which is the smaller investment for your organization?

Use Case Decision Matrix

Use CaseCDKTerraformWhy
Serverless applicationsBestGoodCDK L3 constructs for Lambda, API Gateway reduce boilerplate significantly
Container orchestration (ECS/EKS)BestGoodCDK patterns like ApplicationLoadBalancedFargateService simplify complex setups
Multi-account AWS OrganizationsGoodGoodBoth work well; CDK if developers manage, Terraform if centralized ops team
Network infrastructure (VPC, Transit Gateway)GoodBestTerraform's mature modules and declarative nature fit network configs well
Multi-cloud deploymentsNoBestCDK doesn't support multi-cloud; Terraform is purpose-built for this
Data engineering pipelinesGoodGoodCDK if Python-heavy team, Terraform if diverse data sources across clouds
Kubernetes infrastructureNoBestTerraform has Kubernetes provider; CDK doesn't (use CDK8s for K8s resources)
Third-party SaaS (GitHub, Datadog)NoBestOnly Terraform supports non-AWS providers

For multi-account architectures, see my guide on AWS multi-account best practices.

Migration Strategies and Hybrid Approaches

What if you choose wrong, or what if your requirements change?

Can You Use Both Tools Together?

Yes, hybrid approaches are possible. Some organizations use both tools with clear boundaries:

Common patterns:

  • CDK for application infrastructure (Lambda, ECS, API Gateway)
  • Terraform for foundational infrastructure (VPC, IAM, shared resources)
  • Separate boundaries by team or project

Challenges:

  • Two tools to maintain and learn
  • Potential for resource conflicts
  • Complexity in CI/CD pipelines
  • Cross-tool state sharing requires data sources

When hybrid makes sense:

  • Gradual migration from one tool to another
  • Different teams with different expertise
  • Leveraging strengths of both (CDK constructs + Terraform multi-cloud)

When hybrid adds complexity: Small teams, simple infrastructure, limited expertise. In these cases, pick one.

Migrating from Terraform to CDK

CDK Migrate feature (relatively new) converts existing infrastructure to CDK:

  • Import CloudFormation templates
  • Import deployed CloudFormation stacks
  • Import resources created outside IaC
  • Generates CDK application from existing infrastructure

Migration strategy:

  1. Use cdk migrate to generate initial CDK code from Terraform-managed resources
  2. Review and refactor generated code (will likely use L1 constructs initially)
  3. Replace L1 constructs with L2/L3 where possible
  4. Test thoroughly before switching
  5. Destroy Terraform state after CDK manages resources

Challenges:

  • Generated code may not be idiomatic CDK
  • Potential for resource recreation during import
  • Terraform state file references must be resolved

Recommendation: Migrate incrementally rather than all at once.

Migrating from CDK to Terraform

No automated migration tool - this must be done manually.

Migration strategy:

  1. Use terraform import to import existing CloudFormation-managed resources into Terraform state
  2. Write Terraform configuration matching existing resources
  3. Run terraform plan to verify no changes detected
  4. Test in non-production environment first
  5. Delete CDK stacks after Terraform manages resources

Challenges:

  • Must write Terraform config from scratch
  • CloudFormation-specific resource configurations may not translate directly
  • Import process is resource-by-resource (tedious for large infrastructures)

Alternative: Recreate infrastructure with Terraform (blue/green migration).

Risk Mitigation for Lock-In Concerns

Both tools create lock-in - switching is non-trivial for either direction.

Mitigation strategies:

  • Keep infrastructure simple and modular (easier to rewrite)
  • Document architectural decisions
  • Invest in testing to enable confident refactoring
  • Consider gradual migration over big-bang approach
  • Maintain infrastructure diagrams independent of IaC tool

Honest assessment: If you're worried about lock-in, Terraform's multi-cloud support provides more flexibility by design.

CDK lock-in is twofold: Tool lock-in (CDK itself) + vendor lock-in (AWS via CloudFormation).

Terraform lock-in: Tool lock-in but platform flexibility via providers.

How CDK and Terraform Fit in the IaC Landscape

What about CloudFormation, SAM, Pulumi, and other IaC tools?

Quick Comparison with CloudFormation, SAM, and Pulumi

ToolBest ForLanguageScopeRelationship
CloudFormationAWS-native declarative IaCYAML/JSONAWS onlyCDK synthesizes to CloudFormation
AWS SAMServerless applicationsYAML (simplified)Serverless-focusedSubset of CloudFormation
AWS CDKAWS infrastructure with programmingTypeScript, Python, Java, C#, Go, JSAWS onlyLayer on top of CloudFormation
TerraformMulti-cloud infrastructureHCLMulti-cloudAlternative deployment engine
PulumiMulti-cloud with programmingTypeScript, Python, Go, C#, JavaMulti-cloudSimilar to CDKTF (actively maintained)

Key differentiators:

  • CloudFormation = AWS-native, declarative, YAML/JSON (CDK's underlying deployment engine)
  • CDK = CloudFormation with programming languages (generates CloudFormation templates)
  • Terraform = Multi-cloud, HCL, mature ecosystem (independent deployment engine)
  • Pulumi = Multi-cloud with programming languages (CDKTF's spiritual successor)

When to consider alternatives:

  • CloudFormation directly: If you prefer YAML/JSON and don't need programming abstractions
  • AWS SAM: If you're building purely serverless applications and want simplified syntax
  • Pulumi: If you want CDK-like programming experience with multi-cloud support

For a deeper look at AWS-native IaC options, see my comparison of Control Tower alternatives from console to code.

Conclusion: Making Your Decision with Confidence

Let me summarize what we've covered and give you clear next steps.

Key Takeaways

  1. Neither tool is universally "better" - they're optimized for different scenarios:

    • CDK = AWS-native programming with high-level abstractions and automatic state management
    • Terraform = Multi-cloud declarative with manual state management and mature ecosystem
  2. Your decision criteria should be:

    • Multi-cloud requirement? Terraform
    • Team composition (developers vs ops)? CDK for devs, Terraform for ops
    • Existing expertise? Leverage what you know
    • Testing importance? CDK has native support
  3. Recent changes matter:

    • CDKTF is deprecated (Dec 2025) - "best of both worlds" is gone
    • Terraform's BSL license - understand implications for your org
    • CDK Migrate feature - makes importing infrastructure easier
  4. Migration is possible but non-trivial - plan for lock-in and have a migration strategy

  5. Hybrid approaches work but add complexity - only use if you have specific reasons

Your Next Action Step

If you're choosing CDK:

  1. Install AWS CDK: npm install -g aws-cdk
  2. Follow the AWS CDK Getting Started guide
  3. Read my detailed guide: What is AWS CDK? (A Beginner's Guide)
  4. Learn about bootstrapping: AWS CDK Bootstrap: The Why and the How
  5. Explore project structure best practices: Optimize your AWS CDK Project Structure for Growth

If you're choosing Terraform:

  1. Install Terraform: Follow HashiCorp's installation guide
  2. Read AWS Prescriptive Guidance for Terraform
  3. Set up S3 backend for state management
  4. Explore Terraform Registry for AWS modules
  5. Review Terraform AWS Provider Best Practices

If you're still uncertain:

  1. Build the same simple infrastructure in both tools (S3 bucket + Lambda function)
  2. Evaluate which development experience feels more natural for your team
  3. Run a 2-week proof-of-concept with your actual infrastructure requirements
  4. Make a decision and commit - indecision is more costly than picking either tool

What's your biggest hesitation in making this choice? Drop a comment below and let's discuss.

Need Help With Your AWS CDK Implementation?

We review your CDK infrastructure code for best practices, security compliance, and maintainability. Get actionable recommendations to improve your Infrastructure as Code quality and reduce technical debt.

Share this article on ↓

Subscribe to our Newsletter

Join ---- other subscribers!