Blocks, Labels and Arguments
HCL has only a handful of shapes, and one of them — the block — is everywhere. Once you can take a block apart at a glance, every Terraform file becomes readable.
The rule
Type, labels, braces: arguments set values, nested blocks group them.
Here is Crumb's web server:
resource "aws_instance" "web" {
ami = "ami-0123456789abcdef0"
instance_type = "t3.micro"
root_block_device {
volume_size = 20
}
}- Block type —
resource. It says what kind of block this is. - Labels — the quoted words after the type. A
resourcetakes two: the resource typeaws_instanceand your own local nameweb. - Body — everything inside
{ }. - Arguments —
name = value, likeinstance_type = "t3.micro". Each argument name appears once per block. - Nested blocks —
root_block_device { ... }groups related settings. No=sign, and some nested blocks may repeat.
Different block types take different numbers of labels:
| Block | Labels | Example |
|---|---|---|
terraform |
0 | terraform { ... } |
provider |
1 | provider "aws" { ... } |
variable |
1 | variable "environment" { ... } |
resource |
2 | resource "aws_instance" "web" { ... } |
Value syntax: strings in double quotes, numbers bare (20), booleans true/false, lists ["a", "b"], maps { team = "web" }. Aligning the = signs is a style that terraform fmt applies for you.
The shortcut
Read every block left to right as "a (type) called (labels) with (body)". Then scan the body for =: a line with = is an argument; a name followed straight by { is a nested block.
Type
resource: this block describes a piece of infrastructure.
A common slip is writing root_block_device = { volume_size = 20 }. That is an argument holding a map, which is a different thing, and most providers reject it for a field defined as a block.
Drills
Answer fast — trust the rule.
In resource "aws_instance" "web" { ... }, what is web?
How many labels does a provider block take?
Which line is a nested block?
Which value is a map?
Remember
- A block is type, labels and a body in braces.
- Shortcut:
=means argument; name then{means nested block. - Trap:
name = { }is an argument holding a map, not a nested block.
