The IaC landscape split into two philosophies about a decade ago and hasn't fully resolved the argument since. On one side: declarative configuration languages designed specifically for infrastructure (Terraform HCL, CloudFormation YAML, Bicep). On the other: general-purpose programming languages brought to infrastructure (AWS CDK, Pulumi). Both approaches have won in production at major organizations. Neither is clearly superior.
This comparison covers Terraform, AWS CDK, and Pulumi in depth — how they work, where they excel, where they struggle, and which makes sense for different team situations. It isn't a beginner introduction to any of these tools; if you're choosing between them for a real project, this assumes you've at least skimmed each one.
The core philosophical difference
Terraform's HCL is a purpose-built configuration language. It's not Turing-complete (no arbitrary loops, no recursion, limited conditionals). This is by design: HashiCorp's position is that infrastructure definitions should be readable, predictable, and safe to generate tooling around. When you read a .tf file, you can understand what it creates without executing anything.
CDK and Pulumi take the opposite position: the limitations of configuration languages are a tax on productive engineers. Why invent a domain-specific language when TypeScript already exists? Real programming languages have proper abstractions, test frameworks, package managers, IDE support, and a billion engineers who already know them. Infrastructure should be no different from application code.
Both positions have merit. The choice between them often comes down to who's writing the infrastructure more than which approach is technically superior.
Terraform
Terraform is the default choice for infrastructure-as-code in 2026. It works with every major cloud provider and hundreds of minor ones. The Terraform Registry has thousands of modules — reusable packages for common patterns like VPCs, EKS clusters, and RDS databases. That ecosystem is its most durable advantage.
HCL syntax is approachable. You describe what you want to exist:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.cidr_block, 4, count.index)
availability_zone = var.availability_zones[count.index]
}
Terraform figures out the execution order based on the references between resources. You don't specify steps — you specify the end state.
Where Terraform struggles:
Dynamic resource generation:countandfor_eachare usable but awkward. Generating 20 similar resources with slight variations requires careful HCL gymnastics. CDK and Pulumi can use aforloop.
Abstraction limitations: You can create modules, but you can't do real object-oriented composition. CDK constructs and Pulumi component resources are substantially more powerful for building internal platforms.
Testing: Testing Terraform is harder than it should be.terraform validatechecks syntax;terratest(Go) orpytest-terraformcan do integration tests, but unit testing logic is awkward because HCL isn't executable without a provider.
State management complexity: As covered in depth in the supports Terraform HCL, CDK synthesized JSON, and Pulumi TypeScript/Python — paste your code to see the architecture diagram without deploying anything.
Related articles
↗ Original-Artikel auf dev.to lesenVollständiger Original-BerichtAusführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
SOCIAL SHARE CARD GENERATOR