CloudFormation vs Terraform in 2026: AWS IaC Comparison
CloudFormation vs Terraform compared for AWS in 2026. State management, multi-cloud support, drift detection, modules vs nested stacks, and when to use each.
DevOps
AWS CDK vs Terraform compared for 2026. Programming languages vs HCL, L2 constructs vs modules, state management, multi-cloud
| Criterion | AWS CDK | Terraform |
|---|---|---|
| Language | TypeScript / Python / Java / C# / Go | HCL |
| Cloud support | AWS-first (CDKTF for multi-cloud) | Multi-cloud |
| Abstractions | L1 / L2 / L3 constructs | Modules |
| State | Synthesised to CloudFormation | Self-managed state |
| Best for | AWS teams already in TS/Python | Multi-cloud teams using HCL |
AWS CDK lets you define infrastructure in TypeScript, Python, Java, or Go. Terraform uses HCL. Both deploy AWS resources — but the approach, ecosystem, and tradeoffs are very different.
| Feature | AWS CDK | Terraform |
|---|---|---|
| Language | TypeScript, Python, Java, Go, C# | HCL (declarative) |
| Underlying engine | CloudFormation | Terraform Core |
| Multi-cloud | ❌ AWS only | ✅ 3000+ providers |
| State | AWS-managed (CloudFormation) | Self-managed (S3 + DynamoDB) |
| Abstractions | L2/L3 constructs (high-level) | Modules (community registry) |
| Testing | Jest, pytest (unit tests) | terraform test, Terratest |
| IDE support | Full (TypeScript autocomplete) | Good (HCL plugins) |
| Learning curve | Low if you know the language | Low (HCL is simple) |
| Rollback | ✅ Automatic (CloudFormation) | ❌ Manual |
| Drift detection | ✅ Built-in | ⚠️ terraform plan |
| Community modules | Construct Hub | Terraform Registry |
| Escape hatch | Raw CloudFormation | N/A |
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as rds from 'aws-cdk-lib/aws-rds';
export class AppStack extends cdk.Stack {
constructor(scope: cdk.App, id: string) {
super(scope, id);
const vpc = new ec2.Vpc(this, 'AppVpc', {
maxAzs: 3,
natGateways: 1,
// CDK automatically creates public/private subnets,
// route tables, internet gateway, NAT gateway
});
const db = new rds.DatabaseInstance(this, 'Database', {
engine: rds.DatabaseInstanceEngine.postgres({
version: rds.PostgresEngineVersion.VER_16_3,
}),
vpc,
instanceType: ec2.InstanceType.of(
ec2.InstanceClass.R6G, ec2.InstanceSize.LARGE
),
// CDK auto-creates security group, subnet group,
// parameter group with sensible defaults
});
}
}~20 lines → Creates VPC (3 AZs, public/private subnets, IGW, NAT) + RDS with security groups.
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "app-vpc"
cidr = "10.0.0.0/16"
azs = ["us-east-1a", "us-east-1b", "us-east-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
single_nat_gateway = true
}
resource "aws_db_instance" "main" {
identifier = "production"
engine = "postgres"
engine_version = "16.3"
instance_class = "db.r6g.large"
vpc_security_group_ids = [aws_security_group.db.id]
db_subnet_group_name = aws_db_subnet_group.main.name
# Must explicitly create security group, subnet group
}
resource "aws_security_group" "db" {
vpc_id = module.vpc.vpc_id
# Must define rules explicitly
}
resource "aws_db_subnet_group" "main" {
subnet_ids = module.vpc.private_subnets
}~40 lines → Same result, but you define every component explicitly.
CDK's Level 2 constructs encode AWS best practices automatically:
// L2: Smart defaults + helper methods
const bucket = new s3.Bucket(this, 'Data', {
encryption: s3.BucketEncryption.S3_MANAGED,
versioned: true,
removalPolicy: cdk.RemovalPolicy.RETAIN,
});
// Grant read access — CDK creates the IAM policy automatically
bucket.grantRead(myLambdaFunction);
// This one line creates:
// - IAM policy with s3:GetObject, s3:GetBucket*, s3:List*
// - Scoped to this specific bucket ARN
// - Attached to the Lambda's execution roleIn Terraform, you write the IAM policy manually:
resource "aws_iam_role_policy" "lambda_s3" {
role = aws_iam_role.lambda.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject", "s3:GetBucketLocation", "s3:ListBucket"]
Resource = [
aws_s3_bucket.data.arn,
"${aws_s3_bucket.data.arn}/*"
]
}]
})
}# One project: AWS + Cloudflare + Datadog + PagerDuty
resource "aws_instance" "web" { ... }
resource "cloudflare_record" "dns" { ... }
resource "datadog_monitor" "cpu" { ... }
resource "pagerduty_service" "web" { ... }CDK can't do this — it generates CloudFormation, which is AWS-only.
import { Template } from 'aws-cdk-lib/assertions';
test('creates RDS instance with correct engine', () => {
const app = new cdk.App();
const stack = new AppStack(app, 'Test');
const template = Template.fromStack(stack);
template.hasResourceProperties('AWS::RDS::DBInstance', {
Engine: 'postgres',
DBInstanceClass: 'db.r6g.large',
});
});CDK tests run instantly (no cloud calls) because they test the synthesized CloudFormation template.
# tests/vpc.tftest.hcl
run "vpc_creates_correctly" {
command = plan
assert {
condition = aws_vpc.main.cidr_block == "10.0.0.0/16"
error_message = "VPC CIDR should be 10.0.0.0/16"
}
}bucket.grantRead())Many teams start with CDK for rapid prototyping, then adopt Terraform for production:
Prototype (CDK) → Production (Terraform)
- CDK for fast iteration with L2 constructs
- Terraform for explicit, auditable production configOr the reverse — Terraform teams adopt CDK for complex application stacks where bucket.grantRead() saves hours of IAM policy writing.
CDK and Terraform are both excellent — they optimize for different things. CDK gives you programming language power, smart defaults, and automatic IAM. Terraform gives you explicit control, multi-cloud reach, and the largest IaC ecosystem. If you're AWS-only and your team loves TypeScript, CDK is compelling. If you manage anything beyond AWS or want maximum transparency in your infrastructure code, Terraform is the standard.
CloudFormation vs Terraform compared for AWS in 2026. State management, multi-cloud support, drift detection, modules vs nested stacks, and when to use each.
Pulumi vs Terraform compared for 2026. Programming languages vs HCL, state management, testing, provider support, pricing
Terraform Stacks vs Workspaces compared. Understand when to use Workspaces for environment isolation vs Stacks for multi-component orchestration
Terraform vs OpenTofu compared for 2026. Licensing (BSL vs MPL), feature differences (Stacks, ephemeral resources), provider compatibility