Terraform State Management
Terraform state is a crucial component that tracks the mapping between your configuration and the real-world infrastructure. Understanding state management is essential for working effectively with Terraform.
What is State?
Purpose of State
Terraform stores state about your managed infrastructure and configuration. This state is used to:
- Map real-world resources to your configuration
- Track metadata about resources
- Improve performance by caching resource information
- Enable Terraform to determine what needs to be created, updated, or destroyed
Local State (Default)
Local State File
By default, Terraform stores state locally in a file named terraform.tfstate:
# Default local state
# Stored in terraform.tfstate
# View state
terraform show
# List resources in state
terraform state list
# Show specific resource
terraform state show aws_instance.web
# State file structure (JSON)
{
"version": 4,
"terraform_version": "1.6.0",
"resources": [
{
"type": "aws_instance",
"name": "web",
"instances": [
{
"attributes": {
"id": "i-1234567890abcdef0",
"ami": "ami-0c55b159cbfafe1f0",
"instance_type": "t2.micro",
...
}
}
]
}
]
}
.gitignore to exclude state files.
Remote State Backends
Why Use Remote State?
- ✅ Team Collaboration - Multiple team members can work together
- ✅ State Locking - Prevents concurrent modifications
- ✅ Centralized Storage - Single source of truth
- ✅ Security - State stored securely with encryption
- ✅ Versioning - Keep history of state changes
AWS S3 Backend
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-state-lock"
# Optional: Versioning
versioning = true
# Optional: Server-side encryption
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
}
}
Azure Storage Backend
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "terraformstate"
container_name = "tfstate"
key = "terraform.tfstate"
}
}
GCP Cloud Storage Backend
terraform {
backend "gcs" {
bucket = "terraform-state-bucket"
prefix = "terraform/state"
project = "my-gcp-project"
}
}
Terraform Cloud Backend
terraform {
cloud {
organization = "my-org"
workspaces {
name = "production"
}
}
}
Initializing Remote Backend
# Migrate existing state to remote backend
terraform init -migrate-state
# You'll be prompted to confirm migration
# Type 'yes' to migrate state to the new backend
State Locking
What is State Locking?
State locking prevents concurrent operations from modifying the same state file simultaneously. This ensures consistency and prevents corruption.
S3 + DynamoDB State Locking
# Create DynamoDB table for state locking
resource "aws_dynamodb_table" "terraform_state_lock" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform State Lock Table"
}
}
# Configure backend with DynamoDB
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
State Commands
Viewing State
# Show current state in human-readable format
terraform show
# Show state as JSON
terraform show -json
# List all resources in state
terraform state list
# Show specific resource
terraform state show aws_instance.web
# Show resource at path
terraform state show 'module.vpc.aws_vpc.main'
Modifying State
# Move resource in state
terraform state mv aws_instance.old aws_instance.new
# Move resource to different module
terraform state mv aws_instance.web 'module.vpc.aws_instance.web'
# Remove resource from state (doesn't destroy)
terraform state rm aws_instance.web
# Pull current state
terraform state pull > terraform.tfstate.backup
# Push state (use with caution)
terraform state push terraform.tfstate
Importing Resources
# Import existing resource into state
terraform import aws_instance.web i-1234567890abcdef0
# Import with resource address
terraform import 'module.vpc.aws_instance.web' i-1234567890abcdef0
# Import with multiple instances
terraform import 'aws_instance.web[0]' i-1234567890abcdef0
terraform import 'aws_instance.web[1]' i-1234567890abcdef1
# Prepare import block (Terraform 1.5+)
import {
to = aws_instance.web
id = "i-1234567890abcdef0"
}
# Then run
terraform plan -generate-config-out=generated.tf
State File Structure
Understanding State Format
{
"version": 4,
"terraform_version": "1.6.0",
"serial": 1,
"lineage": "abc123-def456-...",
"outputs": {
"instance_id": {
"value": "i-1234567890abcdef0",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "web",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"ami": "ami-0c55b159cbfafe1f0",
"id": "i-1234567890abcdef0",
"instance_type": "t2.micro",
...
},
"sensitive_attributes": [],
"private": "..."
}
]
}
]
}
State Backups
Automatic Backups
Terraform automatically creates backup files:
# Local backend creates
terraform.tfstate.backup # Automatic backup before modifications
# Remote backends (S3, etc.) support versioning
# Enable versioning on S3 bucket for state history
Manual Backups
# Backup current state
terraform state pull > terraform.tfstate.backup
# Restore from backup
terraform state push terraform.tfstate.backup
State Troubleshooting
State Lock Issues
Error: Error acquiring the state lock
Lock Info:
ID: abc123...
Path: my-terraform-state-bucket/terraform.tfstate
Operation: OperationTypePlan
Who: [email protected]
Version: 1.6.0
Created: 2024-01-15 10:00:00 +0000 UTC
Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.
Solutions:
- Wait for the other operation to complete
- If process crashed, manually unlock:
terraform force-unlock <LOCK_ID> - Check DynamoDB table (for S3 backend) for stale locks
Force Unlock
# Force unlock state (use with caution)
terraform force-unlock <LOCK_ID>
# Get lock ID from error message
State Drift
If resources are modified outside of Terraform, use terraform refresh
to update state with real-world infrastructure.
# Refresh state
terraform refresh
# Refresh specific resource
terraform refresh -target=aws_instance.web
# Plan with refresh
terraform plan -refresh=true
State Corruption
- Restore from backup:
terraform state push terraform.tfstate.backup - Re-import resources:
terraform import <resource> <id> - Recreate state from scratch (last resort)
State Best Practices
- ✅ Always use remote state backends in production
- ✅ Enable state locking to prevent concurrent modifications
- ✅ Enable encryption for state files (at rest and in transit)
- ✅ Enable versioning on state storage (S3, GCS)
- ✅ Use separate state files per environment
- ✅ Never commit state files to version control
- ✅ Use
.gitignoreto exclude state files - ✅ Regularly backup state files
- ✅ Use workspaces or separate directories for environments
- ✅ Monitor state file size (keep it reasonable)
State File Size Management
Large State Files
# Check state file size
ls -lh terraform.tfstate
# If state file is too large:
# 1. Split into multiple workspaces
# 2. Use modules to organize resources
# 3. Remove unused resources from state
Cleaning Up State
# Remove resources that no longer exist
terraform state list
terraform state rm aws_instance.deleted
# Compact state file (removes unused data)
terraform state rm -dry-run # Test first
terraform state rm <unused_resource>
Workspaces
Using Workspaces for Environments
# Create workspace
terraform workspace new development
terraform workspace new staging
terraform workspace new production
# List workspaces
terraform workspace list
# Select workspace
terraform workspace select production
# Show current workspace
terraform workspace show
# Delete workspace
terraform workspace delete development
Workspace-Specific State
# State files per workspace
terraform.tfstate.d/
├── development/
│ └── terraform.tfstate
├── staging/
│ └── terraform.tfstate
└── production/
└── terraform.tfstate
Next Steps
- Modules - Creating reusable modules
- Best Practices - Production-ready practices
- Core Concepts - Deep dive into fundamentals