6.1.2. Remote Backends and the backend Block
💡 First Principle: Moving state to a remote backend centralizes the single source of truth — so every team member and CI run reconciles against the same state — which is the precondition for safe collaboration, remote locking, and encrypted storage.
A remote backend stores state in a shared location: cloud object storage (S3, Azure Blob, GCS), Consul, an HTTP endpoint, or HCP Terraform. You configure it in a backend block inside the terraform block:
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
| Local backend | Remote backend | |
|---|---|---|
| Configuration needed | None (default) | backend block |
| State location | Working directory file | Shared remote store |
| Team collaboration | No | Yes |
| Locking | Local process only | Yes (on supporting backends) |
| Encryption at rest | Up to you / no | Typically yes |
Changing or first configuring a backend requires terraform init, which offers to migrate existing state to the new backend.
⚠️ Exam Trap: Backend configuration changes always require re-running terraform init (often with -migrate-state or -reconfigure). Also, you generally cannot use variables/expressions inside the backend block — it's resolved very early, so values must be literal or supplied via partial configuration / -backend-config.
Reflection Question: Why must you re-run terraform init after changing the backend, in terms of what init is responsible for setting up?