What is Terraform state?
Terraform records real infrastructure in terraform.tfstate. That file maps your configuration to cloud resources so Terraform knows what exists, what changed, and what to create or destroy.
Terraform code
↓
Cloud resources
↓
terraform.tfstate
Important local files:
terraform.tfstate
terraform.tfstate.backup
Never edit terraform.tfstate by hand. Prefer terraform state commands, and never commit state that contains secrets to a public repo.
Inspect state
terraform show
terraform state list
terraform state show aws_instance.exampleWhy remote state?
Local state on one laptop does not scale to a team. Remote state gives you:
Team collaboration
↓
State locking
↓
Centralized storage
S3 backend
Store state in an S3 bucket. Modern Terraform can lock with an S3 lock file (use_lockfile = true). Some teams still use a DynamoDB table for locking — both patterns appear in AWS examples.
Backend block
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# Enable AFTER the bucket (and optional lock table) exist
backend "s3" {
bucket = "terraform-state-file-test-1234"
key = "global/s3/terraform.tfstate"
region = "ap-south-2"
use_lockfile = true
encrypt = true
}
}Bootstrap resources (create before enabling the backend)
provider "aws" {
region = "ap-south-2"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "terraform-state-file-test-1234"
lifecycle {
prevent_destroy = true
}
tags = {
Name = "Terraform State Bucket"
}
}
resource "aws_dynamodb_table" "terraform_locks" {
name = "terraform-up-and-running-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
tags = {
Name = "Terraform State Locks"
}
}
resource "aws_instance" "ec2_instance" {
ami = "ami-0199ac7c9fbf9ed83"
instance_type = "t3.micro"
tags = {
Name = "terraform-ec2-instance"
}
}
output "instance_id" {
value = aws_instance.ec2_instance.id
}
output "s3_bucket_arn" {
value = aws_s3_bucket.terraform_state.arn
}
output "dynamodb_table_name" {
value = aws_dynamodb_table.terraform_locks.name
}Typical workflow:
- Create the bucket (and lock table if you use DynamoDB locking) with local state.
- Add the
backend "s3"block. - Run
terraform init -migrate-stateto move state to S3.
Bucket names must be globally unique. Change terraform-state-file-test-1234 to something only your account will use, and enable versioning on the bucket in real projects.