Skip to main content
RunBook Academy

TerraformIX · State: The Core Production ConceptState

State: The Core Production Topic

Foundation⏱ ~28 min🧪 Lab requiredbashterraform

What you'll learn

  • Explain why Terraform requires state
  • Describe what state contains and what it does not
  • Recognise the consequences of state and reality disagreeing
  • Identify why state is the deepest production topic in the course

Prerequisites

Verified against Terraform CLI 1.9.x · OpenTofu 1.7.x · HCL 2.0 · bpg/proxmox provider 0.66+ · hashicorp/local provider 2.5+ · hashicorp/null provider 3.2+ · hashicorp/random provider 3.6+ · hashicorp/http provider 3.4+ · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · 2026-08-12

Not yet marked complete on this device.

State is the deepest production topic in this course. Every other Terraform concept — modules, environments, CI/CD, policy — is a tool for controlling the blast radius of state. If you read only one lesson in the course, read this one.

Why Terraform needs state

Three reasons, all of them operational.

State lets Terraform know what already exists

Without state, Terraform would have to ask the provider for every resource on every run. For a 5,000-resource estate, that is 5,000 API calls before any work begins. With state, Terraform reads the local JSON and asks only about resources it suspects might have changed.

State lets Terraform map resource addresses to real-world objects

A terraform plan needs to know: “for the resource declared as aws_instance.web in the configuration, what is the corresponding EC2 instance ID in AWS?” The provider returns that ID once, after the first apply. The state stores it. The next plan does not have to ask again.

State lets Terraform propose safe operations

Without state, Terraform cannot know whether an apply would:

  • Create a brand-new resource (resource not in state, not in real world).
  • Update an existing resource (resource in state, matches real world, configuration differs).
  • Destroy an existing resource (resource in state, matches real world, no longer in configuration).
  • Replace an existing resource (resource in state, configuration requires a change that the provider cannot make in-place).

Each of these decisions is operational. Create-new in production costs money. Destroy on a database is catastrophic. The state file is what lets Terraform make the correct decision.

What state contains

A state file is JSON. The fields that matter operationally:

FieldWhat it holdsWhy it matters
versionState schema versionDetermines which terraform version can read it
terraform_versionThe version that wrote the fileDetects stale state
serialMonotonic counterBumped on every write; ordering signal
lineageUUIDIdentifies the lineage; rolled on terraform state mutations
outputsLast computed valuesAvailable for terraform output and downstream config
resourcesOne entry per resourceThe actual mapping from address to real-world ID
resource_instances[i].attributesThe attributes the provider returnedWhat was true at the last refresh
resource_instances[i].dependenciesComputed dependenciesCross-reference for ordering

The state does not contain:

  • The users .tf configuration.
  • The variable values that resolved during the last apply.
  • The output values that have not been computed.
  • Any history of past plans.

The state is a snapshot of what Terraform believed the world looked like at the last refresh. It is not a journal.

What state does not know

The state knows what the provider last told it. It does not know what the provider did not report. A typical example:

resource "aws_instance" "web" {
  ami           = "ami-0e1bed4f"
  instance_type = "t3.medium"
  tags = {
    Name = "web-01"
  }
}

After apply, the state has the instance_type, the ami, the id, and the tags. It does not have the route table, the security group ingress rules, the EBS volume ID, the IAM instance profile, or any of the dozens of real-world attributes a describe-instances would return. The state is a summary along the schema the provider chose to expose.

This is intentional. Storing every attribute would make the state unboundedly large and would surface every API change as a Terraform state change. The provider decides what to expose; Terraform stores what it is told.

The drift problem

State is a snapshot of the past. The real world is now. The two can disagree:

On Monday:    Terraform applies; state records "web-01 has tags {Name=web-01}"

On Tuesday:   An engineer runs `aws ec2 create-tags --resources i-0abc
              --tags Key=Environment,Value=production`

On Wednesday: Terraform runs again. Configuration says
              tags = {Name = "web-01"}. State says tags = {Name = "web-01"}.
              Provider refresh says tags = {Name = "web-01", Environment = "production"}.

What does Terraform do?

The answer is nothing, until the engineer adds Environment = "production" to the configuration. The provider refresh detects the drift, Terraform updates its internal model, and the next plan shows:

~ tags["Environment"] = "production" → "production"

It does not propose to remove the tag. It believes the tag is already in the real world. The configuration was always silent on Environment; the state was less informative than reality.

What happens when state is wrong

State is wrong in many ways. The course treats each in depth later, but the four canonical cases are:

FailureSymptomRecovery
State is lostPlan proposes to create everything from scratchRestore from backup; never apply blindly
State is corruptedterraform plan fails with a JSON parse errorRestore from backup; do not edit by hand
State is stalePlan proposes unexpected changesRefresh first; investigate the diff
State is wrongPlan proposes a correct change to the wrong resourceCompare every address to the real resource; fix manually with terraform state

The wrongest thing an engineer can do at this point is delete the state file and rerun terraform apply. That tells Terraform “the real world is empty”, and the next plan will propose to create duplicate resources, fail to do so in production, or — if the provider permits overwriting — destroy and recreate real infrastructure without warning.

What “lost state” means in practice

If state is lost, three things are true simultaneously:

  1. The real-world infrastructure still exists.
  2. Terraform does not know the real-world infrastructure exists.
  3. The configuration file describes from scratch what should exist.

The plan will then propose to create everything from scratch. If that plan is applied, Terraform will try to create duplicates of everything that exists. The providers behaviour depends on the resource type:

  • Some resources will fail because the real-world identifier (e.g. a DNS name or a S3 bucket name) is unique.
  • Some resources will silently overwrite the existing one.
  • Some resources will create shadow copies in addition to the originals.

The recovery procedure is:

  1. Stop. Do not apply.
  2. Investigate what the real world looks like.
  3. Restore state from backup, or rebuild state by importing each resource individually.
  4. Plan again and verify the plan is empty.

The course has a dedicated lab for this in Part CXI.

Treat state as production data

The state file:

  • May contain secrets. A database password argument is stored in state in plain text unless marked sensitive. A deploy_key is stored in plain text. The course returns to this in Part LIV.
  • Must be encrypted at rest. If the state is remote, the remote backend should encrypt it. If the state is local, the disk should be encrypted.
  • Must be access-controlled. Anyone who can read the state can read the secrets and the topology. Anyone who can write the state can rewrite Terraforms model of the world.
  • Must be backed up. The course recommends daily backups with offsite copies, and treats the loss of state as a data-loss incident.
  • Must not be in Git. The state is a binary blob; it grows monotonically; it changes on every apply; and committing it leaks the topology and often the secrets.

The mental model

A clean way to think about Terraform state:

Configuration    ─┐
                   │  terraform plan
State             ─┤  ────────────────►  Plan output

Real world        ─┘
(provider refresh)

The plan is a proposal based on the three sources of truth.

  • If the configuration matches what state believes about the real world, the plan is empty.
  • If the configuration differs from state, the plan proposes to change the real world.
  • If state differs from the real world, the plan proposes to change the real world based on a stale model — the configuration is applied to whatever state thinks, which may not be the real world.

The plan output is the only place where Terraform tells you what it is about to do. The plan is not a side-effect; it is the operational artefact. Read it. Compare it to your expectation. Apply only when the plan matches what you want.

What the state tells you

The state is the only honest record of what Terraform believes exists. If you want to know what Terraform thinks your infrastructure is, read the state.

# List everything Terraform knows about
terraform state list

# Show the details of one resource
terraform state show aws_instance.web

# Show the full state
terraform show

These commands are read-only. The state-mutating commands (state mv, state rm, state replace-provider) are the subject of Part XXXVI.

What you should take away

  1. State is the central production concern. Every other Terraform concept serves state.
  2. State may be wrong. Backup, version, and audit state as carefully as you would any production database.
  3. The plan is the proposal. Read it. Compare it. Do not apply without understanding it.
  4. State and reality can disagree. When they do, the plan proposes to apply the configuration to whatever Terraform believes, which may not be what is real.
  5. State is sensitive. It is not in Git. It is encrypted at rest. It is access-controlled. It is backed up.

What comes next

The next lesson is local state: what terraform.tfstate looks like on disk, why it is brittle, and why production teams move to a remote backend.

Knowledge check · 7 questions

  1. Q1. Why does Terraform need state?

  2. Q2. Where should state be stored for production?

  3. Q3. A lost state means lost infrastructure.

  4. Q4. What is the role of the dependency lock file?

  5. Q5. Which of the following are stored in state? (Select all that apply.)

  6. Q6. What is the role of state in plan output?

  7. Q7. A team runs plan and sees no changes. The real world has drifted. They run apply; the apply also shows no changes. What should they investigate?

Passing score: 75%. Answers are checked in this browser.