Module 5, State: The Most Important Concept
What is State
Terraform state is a file (terraform.tfstate) that maps your configuration to real-world resources. It is the source of truth for what Terraform manages.
{
"version": 4,
"resources": [
{
"type": "aws_s3_bucket",
"name": "main",
"instances": [{ "attributes": { "id": "my-bucket", "arn": "arn:aws:s3:::my-bucket" } }]
}
]
}
Without state, Terraform would have no idea what already exists. Every terraform plan would show everything as "to be created" even if it exists in AWS.
State Rules
Never:
- Commit
terraform.tfstateto git, it contains secrets in plaintext - Edit it manually, you will corrupt it
- Delete it, you will lose track of all resources
- Let two people run
terraform applysimultaneously, state will corrupt
Always:
- Add
*.tfstateand*.tfstate.backupto.gitignore - Use remote state for team environments
- Enable state locking
State Commands
terraform state list # list all resources in state
terraform state show aws_s3_bucket.main # show one resource in detail
terraform state rm aws_s3_bucket.main # remove from state (NOT from AWS)
terraform import aws_s3_bucket.main my-bucket # import existing AWS resource
terraform state mv aws_s3_bucket.main aws_s3_bucket.artifacts # rename in state
terraform state pull > backup.tfstate # backup remote state locally
terraform state rm is how you stop managing a resource without deleting it. terraform state mv is how you rename a resource in your config without destroying and recreating it in AWS.
Drift Detection
Drift occurs when someone changes infrastructure outside of Terraform:
terraform refresh # sync state with real AWS state
terraform plan # shows drift as changes to be reverted
Example: someone manually adds a tag in the AWS console. terraform plan shows:
~ resource "aws_s3_bucket" "main" {
~ tags = {
- "ManualTag" = "added-in-console"
}
}
Terraform will remove the manual tag on next apply. Never manually change Terraform-managed resources.
Remote State, S3 + DynamoDB
Local state is only for personal projects. Teams must use remote state:
terraform {
backend "s3" {
bucket = "my-company-terraform-state"
key = "finpay/production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock"
}
}
Bootstrap (run once before everything else)
# bootstrap/main.tf
resource "aws_s3_bucket" "terraform_state" {
bucket = "my-company-terraform-state"
}
resource "aws_s3_bucket_versioning" "terraform_state" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration { status = "Enabled" }
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute { name = "LockID"; type = "S" }
}
Lab 4, Remote State Setup
# Step 1: Create bootstrap resources
cd bootstrap && terraform init && terraform apply
# Step 2: Add backend block to your project's versions.tf
# Step 3: Re-initialise, Terraform migrates local state to S3
terraform init
# Answer "yes" to migrate existing state
Knowledge Check
- What is the purpose of
terraform.tfstate? - Why should you never commit
terraform.tfstateto git? - What is drift and how does Terraform detect it?
- What is the difference between
terraform state rmandterraform destroy -target? - What does state locking prevent?
- You deleted a resource from the console but not from Terraform. What happens on next
terraform plan? - A new team member runs
terraform applywhile you are already running one. What prevents conflict?
- HashiCorp Associate Obj 9: Understand Terraform Cloud capabilities
- HashiCorp Associate Obj 6c: Describe when to use terraform import
- AWS DevOps Pro Domain 2: Infrastructure as Code, state management