📜 HCL & Resource Anatomy

Every .tf file is built from the same handful of block types. Learn to read one, and you can read them all.

1. HCL — HashiCorp Configuration Language

Terraform files use HCL: a language designed to be readable by humans and structured enough for machines. Everything is a block — a keyword, optional labels, and { } containing arguments:

resource "aws_instance" "web" { ...arguments... } block typelabel 1 (resource TYPE)label 2 (YOUR name)

2. A Real Config, Fully Labeled

Three blocks working together — every colored zone on the left is explained on the right:

# main.tf terraform {   required_providers {     aws = {       source = "hashicorp/aws"     }   } } provider "aws" {   region = "us-east-1" } resource "aws_instance" "web" {   ami = "ami-0abcd1234"   instance_type = "t3.micro"   tags = {     Name = "taskmanager-web"   } } terraform BLOCK — settings for Terraform itself Which provider plugins does this config need, and from where? "hashicorp/aws" downloads from the official Terraform Registry. Usually also pins the Terraform CLI version. Runs once, when you type "terraform init". provider BLOCK — HOW to connect Configures the AWS plugin: which region, which credentials/profile to use. resource BLOCK — WHAT to build Type: "aws_instance" (a specific AWS EC2 machine). Name: "web" — YOUR internal nickname, used as aws_instance.web elsewhere in this config. Arguments inside set its actual properties (ami, size, tags...).
The pattern that repeats everywhere: BLOCK_TYPE "label" "name" { arguments }. Some blocks need two labels (resource, data), some need one (provider, module, variable), some need none (terraform, locals). The shape is always the same.

3. Referencing One Resource From Another

Resources aren't isolated — you constantly point one at another using TYPE.NAME.ATTRIBUTE:

resource "aws_instance" "web" {
  ami           = "ami-0abcd1234"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.app.id   # ← points at the subnet resource below
}

resource "aws_subnet" "app" {
  vpc_id     = aws_vpc.main.id
  cidr_block = "10.0.1.0/24"
}
🔗 Analogy: This is exactly like a spreadsheet formula pointing at another cell (=A1+B2). When the subnet's ID changes, the instance automatically uses the new value — and Terraform automatically figures out it must create the subnet before the instance that needs it (more on this dependency graph in Chapter 5).

4. Comments & Formatting

# single-line comment
// also valid, same meaning
/* multi-line
   comment */
$ terraform fmt      # auto-formats all .tf files to canonical style
$ terraform validate # checks syntax + internal consistency, no cloud calls
Habit to teach on day one: run terraform fmt before every commit. Every professional Terraform repo has consistently indented, aligned = signs — because everyone just runs fmt instead of manually aligning anything.
🔓 You're reading a free chapter of Terraform — the first two are open.
Unlock the rest of this course with a one-time payment.
Unlock this course →
🔓 See course prices