Terraform 0.12 is the biggest update in Terraform’s history, introducing HCL2 (HashiCorp Configuration Language 2). It addresses the major pain points of 0.11: type constraints, complex interpolations, and limited support for loops. This guide demonstrates how to refactor your infrastructure code to leverage the power of HCL2.
First-Class Expressions
Gone are the ‘${…}’ wrappers for everything. HCL2 supports first-class expressions.
# Terraform 0.11 (Old)
resource "aws_security_group" "example" {
vpc_id = "${var.vpc_id}"
name = "sg-${var.environment}"
}
# Terraform 0.12 (New)
resource "aws_security_group" "example" {
vpc_id = var.vpc_id # No modification needed
name = "sg-${var.environment}"
}
Dynamic Blocks
Creating repeating nested blocks (like ingress rules) was a nightmare in 0.11. dynamic blocks solve this elegantly.
variable "ingress_ports" {
type = list(number)
default = [80, 443, 8080]
}
resource "aws_security_group" "web" {
name = "web-sg"
dynamic "ingress" {
for_each = var.ingress_ports
content {
from_port = ingress.value
to_port = ingress.value
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
}
For Loops and Map Transformations
HCL2 brings Python-like list comprehensions to Terraform.
output "instance_private_ips" {
# Return a map of ID => IP
value = {
for instance in aws_instance.web :
instance.id => instance.private_ip
}
}
# Filtering a list
output "admin_users" {
value = [
for u in var.users :
u.name
if u.is_admin
]
}
Rich Type System
We can now define complex object structures for input variables, enabling strict validation.
variable "node_pools" {
type = map(object({
machine_type = string
min_count = number
max_count = number
labels = map(string)
}))
default = {
"pool-1" = {
machine_type = "n1-standard-1"
min_count = 1
max_count = 3
labels = { env = "dev" }
}
}
}
Key Takeaways
- Upgrade Tool: Use `terraform 0.12upgrade` to auto-fix syntax specific to 0.12.
- Dynamic Blocks: Replace hacky module logic for repeated nested blocks.
- Strict Typing: Use `object()` and `map()` to enforce configuration contracts.
- Generalized Splat: `aws_instance.web[*].id` works everywhere now.
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.