Terraform state is the mechanism that allows Terraform to map your configuration to real-world infrastructure, track resource metadata, and determine what changes need to be made on the next plan or apply. Understanding state is critical for safely running Terraform in production.
What is Terraform State?
The state file (terraform.tfstate) is a JSON file that stores:
- The resources Terraform manages, with their configuration and attributes
- The mapping between Terraform resource addresses and real resource IDs
- Cached attribute values (to avoid unnecessary API calls on plan)
- Metadata for dependencies and module structure
When you run terraform plan, Terraform compares the state (current known state) with your configuration (desired state) and the live infrastructure (via provider API calls) to produce a diff.
State File Risks
- Never commit
terraform.tfstateto Git - Add
*.tfstateand*.tfstate.backupto.gitignore - Use a remote backend with encryption and access controls
Local vs Remote State
| Local State | Remote State | |
|---|---|---|
| Location | terraform.tfstate on disk | S3, GCS, Terraform Cloud, Azure Blob, etc. |
| Team use | Not suitable | Essential for teams |
| Locking | No | Yes (prevents concurrent applies) |
| Encryption | No | Yes (at rest + in transit) |
| History | Only .backup | Versioned (S3 versioning) |
Configuring an S3 Remote Backend
terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "production/us-east-1/infra/terraform.tfstate"
region = "us-east-1"
encrypt = true # encrypt at rest using S3 SSE
dynamodb_table = "terraform-state-lock" # DynamoDB table for state locking
}
}
The DynamoDB table needs a string partition key named LockID. Terraform creates and releases a lock on this table during apply — preventing two people from applying simultaneously.
terraform state Commands
# List all resources in state
terraform state list
# Show details of a resource in state
terraform state show aws_instance.web
# Move a resource to a new address (after renaming in config)
terraform state mv aws_instance.old aws_instance.new
# Remove a resource from state (stop managing, don't destroy)
terraform state rm aws_instance.web
# Pull remote state to local (for inspection)
terraform state pull > state.json
# Push local state to remote (use with caution)
terraform state push state.json
Importing Existing Resources
If infrastructure was created manually or by another tool, bring it under Terraform management:
# Import an existing S3 bucket
terraform import aws_s3_bucket.logs my-existing-bucket-name
# Import an existing EC2 instance
terraform import aws_instance.web i-0abcdef1234567890
After importing, run terraform plan to see if the configuration matches the imported resource. Adjust the configuration to eliminate any planned changes.
State Locking
When Terraform modifies state (during apply, destroy, or state manipulation), it acquires a lock on the state backend. If another process holds the lock, Terraform will wait or fail. This prevents state corruption from concurrent runs.
If a Terraform run is forcibly terminated (CTRL+C twice, process killed), the lock may remain. Use terraform force-unlock LOCK_ID to manually release it — only do this if you're certain no apply is running.
Next: Modules — how to structure and reuse Terraform code across projects and teams.