The backend determines where Terraform stores state. Local files work for learning, but teams need remote backends for collaboration, locking, and disaster recovery.
Why Remote Backends
| Feature | Local | Remote |
|---|---|---|
| Team collaboration | ā | ā |
| State locking | ā | ā |
| Encryption at rest | Manual | ā |
| Versioning/backup | Manual | ā |
| CI/CD friendly | ā | ā |
S3 Backend (AWS)
The most common setup:
Create Backend Infrastructure
# bootstrap/main.tf ā run this first, once
provider "aws" {
region = "eu-west-1"
}
resource "aws_s3_bucket" "state" {
bucket = "myorg-terraform-state"
}
resource "aws_s3_bucket_versioning" "state" {
bucket = aws_s3_bucket.state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
bucket = aws_s3_bucket.state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
}
}
}
resource "aws_s3_bucket_public_access_block" "state" {
bucket = aws_s3_bucket.state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_dynamodb_table" "lock" {
name = "terraform-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}Configure Backend
# backend.tf
terraform {
backend "s3" {
bucket = "myorg-terraform-state"
key = "production/network/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "terraform-lock"
encrypt = true
}
}State Key Organization
s3://myorg-terraform-state/
production/
network/terraform.tfstate
database/terraform.tfstate
application/terraform.tfstate
staging/
network/terraform.tfstate
database/terraform.tfstate
shared/
dns/terraform.tfstate
iam/terraform.tfstateAzure Blob Backend
terraform {
backend "azurerm" {
resource_group_name = "terraform-state-rg"
storage_account_name = "myorgterraformstate"
container_name = "tfstate"
key = "production.terraform.tfstate"
}
}Master this topic with hands-on labs
Go beyond reading ā build real projects in sandboxed environments with expert video guidance.
Browse Courses āGCS Backend (Google Cloud)
terraform {
backend "gcs" {
bucket = "myorg-terraform-state"
prefix = "production/network"
}
}Terraform Cloud Backend
terraform {
cloud {
organization = "my-org"
workspaces {
name = "production-network"
}
}
}Or with workspace tags:
terraform {
cloud {
organization = "my-org"
workspaces {
tags = ["production", "network"]
}
}
}Partial Configuration
Keep secrets out of code:
# backend.tf
terraform {
backend "s3" {
key = "production/terraform.tfstate"
}
}# Pass config at init time
terraform init \
-backend-config="bucket=myorg-terraform-state" \
-backend-config="region=eu-west-1" \
-backend-config="dynamodb_table=terraform-lock"
# Or use a file
terraform init -backend-config=backend.hcl# backend.hcl (gitignored)
bucket = "myorg-terraform-state"
region = "eu-west-1"
dynamodb_table = "terraform-lock"
encrypt = trueState Locking
DynamoDB provides locking for S3 backend:
# Lock is acquired automatically during plan/apply
terraform plan
# Acquiring state lock...
# ...
# Releasing state lock...
# Force unlock (use with caution!)
terraform force-unlock LOCK_IDGet weekly IT automation tips
Docker, Ansible, Terraform, MLOps ā curated insights delivered to your inbox. No spam.
Subscribe Free āMigrating Backends
Local ā S3
# 1. Add backend configuration
terraform {
backend "s3" {
bucket = "myorg-terraform-state"
key = "app/terraform.tfstate"
region = "eu-west-1"
}
}# 2. Re-initialize
terraform init
# Terraform will ask: "Do you want to copy existing state to the new backend?"
# Answer: yesS3 ā Terraform Cloud
# 1. Update backend config to cloud block
# 2. Run terraform init
terraform init
# Terraform detects backend change, offers to migrateExport/Import State
# Export
terraform state pull > state.json
# Import to new backend
terraform state push state.jsonCI/CD Integration
# GitHub Actions
- name: Terraform Init
run: terraform init -backend-config=backend.hcl
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
- name: Terraform Plan
run: terraform plan -out=tfplan
- name: Terraform Apply
if: github.ref == 'refs/heads/main'
run: terraform apply tfplanBest Practices
| Practice | Why |
|---|---|
| Enable versioning on state bucket | Recover from corruption |
| Enable encryption | State contains secrets |
| Use DynamoDB locking | Prevent concurrent modifications |
| Block public access | State is sensitive |
| Use separate state per component | Limit blast radius |
| Use partial config for secrets | Keep creds out of code |
| Tag state resources | Know what manages them |
What's Next?
Our Terraform for Beginners course covers remote backends, state management, and team workflows. First lesson is free.
---
Ready to go deeper? Check out our hands-on course: Terraform for Beginners ā practical exercises you can follow along on your own machine.
Ready to learn by doing?
Stop reading tutorials ā start building. Expert video courses with hands-on labs in real sandboxed environments.
Related Articles
Terraform State Management Guide
Master Terraform state management. Remote backends, state locking, import commands, state moves, and disaster recovery procedures.
Tofu vs Terraform Comparison
OpenTofu forked Terraform after the BSL license change. Compare features, compatibility, licensing, and ecosystem to decide which IaC tool fits your team.
GitHub Actions CI/CD for Terraform
Automate Terraform with GitHub Actions. Plan on PR, apply on merge, remote state locking, and secure secrets for IaC pipelines.
Terraform for Beginners Guide
Everything you need to know to start using Terraform for Infrastructure as Code. From installation to your first deployment on AWS.
Terraform CDK vs HCL Comparison
Terraform CDK lets you write infrastructure in TypeScript, Python, or Go instead of HCL. Compare CDKTF and HCL for real-world use cases and learn when each.
Terraform CI/CD Pipelines
Build CI/CD pipelines for Terraform using GitHub Actions. Automate plan, apply, and destroy workflows with safety checks.
Explore topics
Browse more articles on the topics covered here.