Skip to content

Lesson 2 of 7 · 22m

HCL, Resources, and State: The Mental Model

Resources are declared objects; state is Terraform's memory of what exists — understand that pairing and everything else follows.

Terraform's model is deceptively simple: HCL files declare resources; a state file records what Terraform has created; plan diffs the declaration against state+reality; apply reconciles. The whole tool is those four ideas.

HCL: resources and references

resource "aws_security_group" "web" {
  name = "web-sg"
  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "web" {
  ami           = "ami-0abc123"
  instance_type = "t3.micro"
  vpc_security_group_ids = [aws_security_group.web.id]  # the graph edge
}

aws_instance.web referencing aws_security_group.web.id is the dependency graph — Terraform orders creation automatically. Attributes on resources become references elsewhere; output blocks publish them for the next layer.

State is the source of truth

terraform.tfstate records every resource Terraform manages — ID, attributes, dependencies. It's how plan knows "no changes" vs "recreate": state is Terraform's memory, and it must match reality. Two rules that keep it honest:

  • Never edit state manually — terraform state subcommands exist for surgical fixes.
  • Never lose state — it's encrypted-at-rest worthy and remote-backed on any team setup.

Try it yourself

The dependency graph explains why order doesn't matter in HCL:

// Terraform builds this graph from references, then walks it
const graph = {
  "aws_security_group.web": [],
  "aws_instance.web": ["aws_security_group.web"], // depends on
};
// Creation order: SG first, then instance — declared order is irrelevant.
console.log(Object.keys(graph).sort());

Field notes

  • terraform show reads state; terraform import adopts existing resources into it.
  • Data sources (data "aws_ami") read reality without managing it — for referencing infra you don't own.
  • State leaks: it contains attribute values including sensitive ones — remote state with encryption + access control is not optional on real setups.