Why do we need more than HCL?
Think of HCL (HashiCorp Configuration Language) like a very detailed order form at a restaurant. You fill in the boxes — "I want a VPC, size medium, with two subnets" — and the kitchen (AWS) makes it. That works great for simple orders. But what if you need to order the same meal for 50 tables, each with slight variations? Filling out 50 forms by hand is tedious, error-prone, and hard to update when the menu changes.
Terraform and HCL are fantastic tools that revolutionized infrastructure by allowing us to define it declaratively. But HCL is a configuration language, not a full programming language. As your infrastructure grows complex, you hit real limits:
- Boilerplate: Creating a standard VPC with public/private subnets in HCL requires dozens of lines of repetitive resource definitions. Multiply that across 10 environments and you have hundreds of lines of near-identical code.
- Limited Logic: Complex conditional branching, recursive data transformations, or sharing reusable object-oriented abstractions is awkward in pure HCL.
count,for_each, anddynamicblocks can only take you so far. - Skill Barriers: Your application developers know Python or TypeScript, not HCL. This creates an artificial wall between "Dev" and "Ops" — developers who could contribute to infrastructure don't, because they'd have to learn a new language first.
- Testability: Unit testing HCL is difficult. You can use tools like
terratest, but you're writing Go to test HCL, which is a context switch. Testing Python with pytest or TypeScript with Jest is far more natural.
Enter Abstractions
Tools like the AWS Cloud Development Kit (CDK) and Pulumi let you define infrastructure using real general-purpose programming languages — TypeScript, Python, Go, Java, and C#. This unlocks the full power of software engineering: classes, inheritance, loops, conditionals, testing frameworks, and package managers (npm, pip, go mod). You aren't just configuring; you are programming your cloud.
The mental model shift is significant. In HCL, you describe what you want. In CDK or Pulumi, you write code that, when executed, describes what you want. The result is the same — cloud resources get created — but the path there gives you the full expressiveness of a programming language.
Key Point: Real programming languages eliminate boilerplate and let teams use the tools they already know. The tradeoff is added complexity — you now have a build step, a runtime, and a dependency graph to manage. For small, stable infrastructure, HCL may still be the right choice. For large, dynamic, or developer-owned infrastructure, CDK and Pulumi shine.