Terraform State Management & Team Collaboration Best Practices
Terraform’s State file is the core of infrastructure as code — it records the mapping between real resources and your configuration. Poor State management in a team setting can lead to resource drift, lock conflicts, or even accidental infrastructure destruction.
This post summarizes State management best practices, covering remote backend configuration, state locking, workspace isolation, and daily operational tips.
1. Never Use Local State
By default, Terraform stores state in a local terraform.tfstate file, which is disastrous for team collaboration:
- Multiple people running apply simultaneously will overwrite each other
- Losing the State file means Terraform loses track of all resources
Configure a remote backend (S3 example):
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}Key points:
encrypt = trueensures State is encrypted at restdynamodb_tableprovides state locking to prevent concurrent writes
2. State Locking
State locking ensures only one operation can modify the State at a time, preventing concurrent conflicts.
| Backend | Lock Mechanism |
|---|---|
| S3 | DynamoDB |
| GCS | Built-in |
| Azure Blob | Blob Lease |
| Consul | KV Lock |
Handling a stuck lock:
# Check current lock info (Lock ID is shown in the error message)
# After confirming no one else is running an operation, force unlock
terraform force-unlock <lock-id>⚠️
force-unlockis a dangerous operation. Always confirm no other apply is in progress before using it.
3. State Isolation Strategies
Option 1: Directory Isolation (Recommended)
Split different environments and modules into separate directories, each with its own State:
infrastructure/
├── modules/
│ ├── vpc/
│ └── ecs/
├── prod/
│ ├── network/
│ │ └── main.tf # state: prod/network/terraform.tfstate
│ └── compute/
│ └── main.tf # state: prod/compute/terraform.tfstate
└── staging/
├── network/
└── compute/Benefits:
- Small blast radius — issues in one directory don’t affect other resources
- Permissions can be controlled at directory granularity
- Faster
plan/applyexecution
Option 2: Workspace Isolation
terraform workspace new staging
terraform workspace new prod
terraform workspace select prodSuitable when configuration differences between environments are minimal. State is automatically isolated by workspace name.
Not recommended for isolating prod and staging, as they share the same code and backend configuration, making accidental operations more likely.
4. Cross-State Data References
When different directories need to share data, use terraform_remote_state:
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "prod/network/terraform.tfstate"
region = "us-east-1"
}
}
# Reference the VPC ID output from the network layer
resource "aws_instance" "app" {
subnet_id = data.terraform_remote_state.network.outputs.subnet_id
}A better alternative is using
datasources to query cloud resources directly (e.g.,aws_vpc), reducing coupling between States.
5. Daily State Operations
# List all resources in the current State
terraform state list
# Show detailed attributes of a resource
terraform state show aws_instance.app
# Remove a resource from State (does NOT delete the real resource)
terraform state rm aws_instance.legacy
# Move a resource to a new address (after code refactoring)
terraform state mv aws_instance.old aws_instance.new
# Import an existing resource into State
terraform import aws_instance.app i-1234567890abcdef0
# Pull remote State locally for inspection
terraform state pull > state.json6. Security Considerations
- State contains sensitive data: Database passwords, keys, etc. are stored in plaintext in State. Always encrypt storage and restrict access.
- S3 Bucket policy: Enable Versioning for State rollback capability; configure Bucket Policy to restrict access.
- State in CI/CD: IAM Roles used in pipelines should follow the principle of least privilege, granting only necessary State read/write permissions.
.gitignoremust include:*.tfstate *.tfstate.backup .terraform/