interview-prep

Crisp answer: State is a JSON file that maps your Terraform configuration to real infrastructure. Terraform uses it to know what exists, what needs to change, and what needs to be destroyed. Without it, Terraform cannot manage infrastructure it did not create.

What state contains:

{
  "version": 4,
  "terraform_version": "1.9.0",
  "resources": [
    {
      "type": "aws_instance",
      "name": "web",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "attributes": {
            "id": "i-0abc123def456",
            "ami": "ami-0abcdef1234567890",
            "instance_type": "t3.micro",
            "private_ip": "10.0.1.5"
          }
        }
      ]
    }
  ]
}

State records every attribute of every resource: IDs, ARNs, IP addresses, and all computed values. When you run terraform plan, Terraform compares the desired state in your .tf files against the recorded state to decide what actions to take.

Why state matters:

  • Dependency tracking: Terraform knows that a security group must exist before the EC2 instance that references it
  • Change detection: If you add a tag to a resource in .tf, state tells Terraform the resource already exists and needs an update, not a create
  • Destroy: Terraform knows which real resources to delete when you remove a block from your config
  • Performance: Terraform reads state instead of calling every AWS API on every plan (the --refresh=false flag skips even that)

Remote state:

Local state (terraform.tfstate) is dangerous for teams — two people running apply simultaneously corrupt it. Use remote state:

# S3 backend with native locking (Terraform >= 1.9)
terraform {
  backend "s3" {
    bucket       = "my-terraform-state"
    key          = "prod/terraform.tfstate"
    region       = "eu-west-2"
    use_lockfile = true   # S3-native locking, no DynamoDB needed in TF 1.9+
  }
}

Before Terraform 1.9 you needed a DynamoDB table for locking:

# Pre-1.9 pattern (still widely used):
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "eu-west-2"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

State locking:

When you run terraform apply, Terraform acquires a lock on the state file. If another apply is running, it fails with a lock error. This prevents concurrent modifications that would corrupt state.

# Force-unlock if a previous apply crashed and left a stale lock:
terraform force-unlock <lock-id>

What to say in the interview:

"State is the source of truth that maps your config to real infrastructure. Terraform reads it on every plan to calculate the diff. Without remote state in a team environment you get corruption from concurrent applies. I always use S3 backend with locking. The important operational thing: if a plan shows unexpected changes, the first thing I check is whether state is out of sync with reality — either because someone made a manual change in the console, or because a previous apply partially completed."


My notes