Terraform Best Practices Every DevOps Engineer Should Follow
Terraform by HashiCorp has become the de facto standard for Infrastructure-as-Code (IaC). But knowing Terraform syntax is just the start — senior engineers follow a set of proven practices that keep infrastructure reliable, secure, and maintainable.
1. Use Remote State with Locking
Never store terraform.tfstate locally in a team environment. Use a remote backend with state locking:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}
2. Structure with Modules
Break your infrastructure into reusable modules. A common pattern:
modules/
vpc/
eks-cluster/
rds/
environments/
dev/
staging/
prod/
3. Use Variables and locals, Never Hardcode
Hardcoded values like AMI IDs, region names, or CIDRs are a maintenance nightmare. Always use variables with sensible defaults and describe their purpose.
4. Pin Provider and Module Versions
Always specify exact version constraints for providers and modules to ensure reproducible infrastructure:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = ">= 1.5.0"
}
5. Separate Environments via Workspaces or Directory Structure
Use separate state files for each environment. The directory-per-environment pattern is more explicit and less error-prone than Terraform workspaces for most teams.
6. Run terraform plan in CI/CD Before Apply
Never apply changes blindly. A well-structured Terraform CI/CD pipeline runs terraform plan on every PR and requires human approval before terraform apply in production.
7. Use Data Sources Over Hardcoded IDs
Instead of hardcoding an AMI ID, use a data source to dynamically look it up. This makes your code portable and automatically picks up updates.
Ready to Practice?
Test your knowledge with our Terraform Interview Questions.