When Terraform creates infrastructure, it needs to remember what it created. Otherwise, how would it know what to update or destroy next time? That memory is called state.
What Is State?
State is a JSON file (terraform.tfstate) that maps our Terraform configuration to real-world resources. When we write resource "aws_s3_bucket" "assets", Terraform stores the actual bucket ID, ARN, and all its properties in state.
Without state, Terraform would have no idea what already exists. It would try to create everything from scratch every time.
Local vs Remote State
By default, state lives in a local file. That’s fine for solo experimentation, but terrible for teams. If two people run terraform apply at the same time with different local state files, things get destroyed or duplicated.
Remote state solves this. We store state in a shared location — usually an S3 bucket with a DynamoDB table for locking.
# Store state remotely in S3
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/infrastructure.tfstate"
region = "ap-south-1"
dynamodb_table = "terraform-locks" # prevents concurrent writes
encrypt = true
}
}
Now everyone on the team reads and writes to the same state. No conflicts.
State Locking
When someone runs terraform apply, the state gets locked. This prevents another person from making changes at the same time. Think of it like a database transaction lock — only one writer at a time.
The DynamoDB table in the example above handles this. If we try to run apply while someone else is already running it, Terraform says “state is locked” and waits.
Why State Matters
- Drift detection — Terraform compares state with what actually exists. If someone manually changed a resource in the console,
terraform plancatches the difference. - Dependency tracking — state records relationships between resources. Terraform knows it needs to create the VPC before the subnet.
- Performance — instead of querying every resource from the cloud API, Terraform reads state to know what exists.
Useful State Commands
# List all resources Terraform is tracking
terraform state list
# Show details of a specific resource
terraform state show aws_s3_bucket.assets
# Remove a resource from state (Terraform forgets it, doesn't delete it)
terraform state rm aws_s3_bucket.legacy
# Move a resource (renamed something in code?)
terraform state mv aws_s3_bucket.old aws_s3_bucket.new
Workspaces
Workspaces let us manage multiple environments (dev, staging, prod) with the same code but separate state files:
terraform workspace new staging
terraform workspace new production
terraform workspace select staging
terraform workspace list
Each workspace gets its own state. We can use terraform.workspace in our config to change behavior per environment.
Modules
As our infrastructure grows, copy-pasting resource blocks is painful. Modules are reusable packages of Terraform configuration. Think of them like functions — we define them once and call them with different inputs.
A module is just a directory with .tf files:
modules/
s3-bucket/
main.tf # resource definitions
variables.tf # input parameters
outputs.tf # exposed values
# modules/s3-bucket/variables.tf
variable "bucket_name" {
type = string
}
variable "environment" {
type = string
default = "dev"
}
# modules/s3-bucket/main.tf
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
# modules/s3-bucket/outputs.tf
output "bucket_arn" {
value = aws_s3_bucket.this.arn
}
Now we call it from our root config:
# Use our module for different buckets
module "app_assets" {
source = "./modules/s3-bucket"
bucket_name = "my-app-assets"
environment = "production"
}
module "logs" {
source = "./modules/s3-bucket"
bucket_name = "my-app-logs"
environment = "production"
}
We can also use modules from the Terraform Registry — thousands of community-maintained modules for common patterns.
In simple language, state is Terraform’s memory of what it built, remote backends make that memory shared and safe, and modules let us stop repeating ourselves. These three concepts are what separate a messy Terraform project from a clean one.