DevOps Peach

Advanced Terraform · State and Teamwork · Lesson 1 of 4

Inside the State File

State maps every resource address in your code to a real object ID; it stores all attributes in plain text, including secrets, and is protected by serial and lineage.

Practice interactively →

Terraform does not scan your infrastructure to find "its" resources. It keeps a state file that maps each address in the code to a real object and stores the last known attributes. Plan = desired config compared with state, after the state was refreshed from the real API.

flowchart LR
  CODE["Code: docker_container.web"] --> PLAN["terraform plan"]
  ST["State: address → id 4f1c2a"] --> PLAN
  API["Real API: Docker daemon"] -->|"refresh"| ST
  PLAN --> DIFF["Diff: add / change / destroy"]
  DIFF -->|"apply"| API
  %% step CODE: The configuration says what should exist, by address.
  %% step ST: The state remembers which real object belongs to each address, with every attribute.
  %% step API: Before planning, Terraform refreshes the state by reading each object from the provider API.
  %% step PLAN: Plan compares the refreshed state with the configuration.
  %% step DIFF: The diff lists what apply will create, update in place, replace or destroy.

What is inside

{
  "version": 4,
  "terraform_version": "1.13.4",
  "serial": 17,
  "lineage": "8b0f6c4e-...",
  "resources": [
    { "mode": "managed", "type": "docker_container", "name": "web",
      "instances": [ { "attributes": { "id": "4f1c2a...", "image": "sha256:...", "env": ["DB_PASSWORD=s3cret"] } } ] }
  ]
}
Field Meaning
serial Increases on every write; an older serial cannot overwrite a newer one
lineage ID created with the state; protects against pushing a state from a different project
resources[].instances[].attributes Every attribute the provider returned, including passwords and keys
outputs Root outputs, readable by others (module 2.4)

Because secrets are stored in plain text, treat state like a password vault: encrypted storage, strict access, never in Git. sensitive = true only hides values from CLI output, not from state.

Inspecting state safely

Command Use
terraform state list Every address
terraform state show 'docker_container.app["web"]' Attributes of one instance
terraform show -json \| jq Whole state as JSON for scripts
terraform plan -refresh-only Show what changed outside Terraform, without proposing config changes
terraform apply -refresh-only Accept those outside changes into state
terraform state pull > backup.tfstate Download a copy before risky surgery

Never edit the JSON by hand and state push it back unless you have a backup and no other choice; the state commands in topic 2.3 do the same jobs safely.

Refresh and performance

Every plan refreshes every resource. In a state with thousands of resources this is slow and hits API rate limits; that is one reason to split states (topic 2.4). -refresh=false skips the refresh for a quick look, but the plan may then be wrong.

Traps: deleting a resource from the state does not delete the real object, it only makes Terraform forget it; and two people running apply on a local state file at the same time will corrupt or lose changes, which is why teams use a remote backend with locking.

Practice interactively →