Reference: Terraform Up & Running (O’Reilly)
Storing Terraform state locally is fine for solo projects, but teams need a shared backend. On AWS, an S3 bucket (state files) plus DynamoDB table (state locking) works well.
Provision S3 & DynamoDB
Create a separate Terraform project to bootstrap the backend:
provider "aws" {
region = "ap-northeast-2"
}
resource "aws_s3_bucket" "terraform_state" {
bucket = "jeongbin-terraform-bucket"
lifecycle {
prevent_destroy = true
}
}
resource "aws_s3_bucket_versioning" "versioning" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "encryption" {
bucket = aws_s3_bucket.terraform_state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
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"
}
}
Apply this once to create the bucket/table.
Configure the Backend
In your main Terraform project:
terraform {
backend "s3" {
bucket = "jeongbin-terraform-bucket"
key = "global/s3/terraform.tfstate"
region = "ap-northeast-2"
dynamodb_table = "terraform-up-and-running-locks"
encrypt = true
}
}
Run terraform init to migrate state to S3. You’ll notice no local .tfstate file—Terraform now reads/writes to S3.
To avoid hardcoding values, use an HCL config file:
# backend.hcl
bucket = "jeongbin-terraform-bucket"
region = "ap-northeast-2"
dynamodb_table = "terraform-up-and-running-locks"
encrypt = true
# backend.tf
terraform {
backend "s3" {
key = "global/s3/terraform.tfstate"
}
}
Initialize with:
terraform init -backend-config=backend.hcl
Workspaces (Environment Isolation)
Terraform workspaces provide isolated state files—handy for staging vs. production.
terraform workspace show # current workspace
terraform workspace new dev # create a new workspace
terraform apply # applies only to that workspace
terraform workspace select default # switch back
In S3 you’ll see separate folders (e.g., env:/dev/terraform.tfstate).
You can even tailor resources per workspace:
resource "aws_instance" "ec2" {
ami = "ami-0ea5eb4b05645aa8a"
instance_type = terraform.workspace == "default" ? "t3.nano" : "t3.medium"
}
This ternary-like expression picks a larger instance type outside the default workspace.