Terraform Associate
Deep Dive
Remote backends are essential for teamwork: they let you share state, enable locking, and keep secrets off the local disk. This guide covers the most commonly used backends and their key differences.
Contents
If you don't configure a backend, Terraform uses the local backend by default. State is stored in terraform.tfstate in the working directory.
✅ Advantages of the local backend
⚠️ Limitations of the local backend
# Explicit local backend (equivalent to the default behavior)
terraform {
backend "local" {
path = "terraform.tfstate" # path of the state file
}
}
# Or simply don't define any backend — local is the defaultThe S3 backend is the most widely used in AWS environments. It stores state in an S3 bucket and, since Terraform 1.11, locks natively with a .tflock file in the same bucket (use_lockfile = true). DynamoDB locking (dynamodb_table) is deprecated.
terraform {
backend "s3" {
bucket = "my-company-terraform-state" # S3 bucket name
key = "prod/vpc/terraform.tfstate" # path of the file inside the bucket
region = "us-east-1" # bucket region
# Native S3 locking (Terraform 1.11+) — creates <key>.tflock in the bucket
use_lockfile = true # without this there is no locking
# Encryption at rest
encrypt = true # SSE-S3 or SSE-KMS
kms_key_id = "arn:aws:kms:..." # optional: use a specific KMS key
# AWS profile (alternative to environment variables)
profile = "my-aws-profile" # optional
}
}
# Legacy (deprecated): dynamodb_table = "terraform-state-lock"
# with a DynamoDB table whose primary key is LockID (String)| Argument | Required | Description |
|---|---|---|
| bucket | ✅ Yes | Name of the S3 bucket where state is stored |
| key | ✅ Yes | Path of the object inside the bucket (e.g.: prod/tfstate) |
| region | ✅ Yes | AWS region of the bucket |
| use_lockfile | ❌ No* | * Without this there is no locking. Native S3 lock (1.11+); replaces dynamodb_table (deprecated). |
| encrypt | ❌ No | If true, enables SSE encryption of the state file |
| kms_key_id | ❌ No | ARN of the KMS key for SSE-KMS (more secure than SSE-S3) |
Azure Storage provides native locking via Blob Leases, without needing an additional resource (just like S3 with use_lockfile).
terraform {
backend "azurerm" {
resource_group_name = "rg-terraform-state"
storage_account_name = "samycompanytfstate" # globally unique name
container_name = "tfstate" # blob container
key = "prod.terraform.tfstate" # blob name
# Authentication (several options):
# 1. ARM_* environment variables (recommended in CI/CD)
# 2. Azure CLI (az login) for local use
# 3. Managed Identity on VMs/AKS
}
}
# Advantage over S3: locking is automatic via Blob Lease
# You don't need an additional resource for lockingGCS also provides native locking, simplifying the setup compared to S3.
terraform {
backend "gcs" {
bucket = "my-company-terraform-state" # GCS bucket name
prefix = "terraform/prod" # prefix for the state objects
# Authentication: uses Application Default Credentials (gcloud auth)
# Or: credentials = "/path/to/service-account.json" (not recommended to hardcode)
}
}
# GCS supports native locking via object locking
# It doesn't need an additional resource (same as Azure, unlike S3)HCP Terraform (formerly Terraform Cloud) has a deeper, special integration beyond traditional storage backends: it doesn't just store the state, it also runs plans and applies remotely.
# Option 1: cloud block (recommended for HCP Terraform)
terraform {
cloud {
organization = "my-company"
workspaces {
name = "prod-vpc" # specific workspace
# Or by tags:
# tags = ["prod", "networking"]
}
}
}
# Option 2: "remote" backend (older form, still supported)
terraform {
backend "remote" {
organization = "my-company"
workspaces {
name = "prod-vpc"
}
}
}
# Authentication: terraform login
# Or: environment variable TF_TOKEN_app_terraform_io🎯 cloud vs remote backend
The cloud block is the modern way to connect to HCP Terraform (introduced in Terraform 1.1). The remote backend is the older method that still works. For new configurations, always use the cloud block.
Partial backend configuration lets you avoid hardcoding sensitive information (credentials, bucket names) directly in the .tf files.
# PARTIAL CONFIGURATION — don't hardcode credentials in the backend block
terraform {
backend "s3" {
# Only the static (non-sensitive) configuration:
region = "us-east-1"
encrypt = true
# bucket and key are passed at init
}
}
# Pass the remaining config in terraform init:
terraform init -backend-config="bucket=my-company-tfstate" -backend-config="key=prod/vpc/terraform.tfstate" -backend-config="use_lockfile=true"
# Or from an HCL file (without the terraform {} block):
# backend.hcl:
# bucket = "my-company-tfstate"
# key = "prod/vpc/terraform.tfstate"
# use_lockfile = true
terraform init -backend-config=backend.hcl
# STATE MIGRATION between backends:
# 1. Change the backend block in the .tf
# 2. Run:
terraform init -migrate-state
# Terraform will ask for confirmation to move the state| Backend | Locking | Native encryption | Extra config for locking |
|---|---|---|---|
| Local | ✅ Yes | ❌ No | None (file lock, same machine only) |
| S3 | ✅ Yes | ✅ Yes | use_lockfile = true (legacy DynamoDB, deprecated) |
| Azure Storage | ✅ Yes | ✅ Yes | None (automatic Blob Lease) |
| GCS | ✅ Yes | ✅ Yes | None (native) |
| HCP Terraform | ✅ Yes | ✅ Yes | None (automatic) |
Did you get this topic?
Test what you just learned
A team wants to use the S3 backend for Terraform state but needs to keep credentials and the bucket name out of the .tf files in the repository. What is the correct solution?
Put what you learned to the test with original Terraform Associate exam questions.
Start Terraform Associate mock examUnlimited mock exams with the Pro plan
Log in to track your progress.