Terraform Patterns
Modern Infrastructure as Code patterns for Terraform, emphasizing modularity, safety, and team collaboration.
Core Principles
| Principle | Implementation |
|---|---|
| Treat as code | Version control, code review, CI/CD |
| Don't Repeat Yourself | Modules for reusable patterns |
| Explicit > Implicit | tfvars over workspaces, directories over conditionals |
| Plan before apply | Always review terraform plan |
| Remote state | Never local state in production |
Note: HashiCorp changed Terraform license (BSL). OpenTofu is the community MPL-2.0 fork.
Standard Module Structure
code
modules/
└── cloud-sql/
├── main.tf # Resources
├── variables.tf # Inputs with validation
├── outputs.tf # Outputs for other modules
├── versions.tf # Provider constraints
├── README.md # Documentation
└── examples/
└── basic/
└── main.tf # Usage example
Design Guidelines
- •Single responsibility - One logical component per module
- •Sensible defaults - Work out-of-the-box
- •Validate inputs - Catch errors early
- •Explicit outputs - Clear contract
- •Semantic versioning - Tag releases
Environment Separation
Recommended: Directory per Environment
code
environments/
├── staging/
│ ├── main.tf
│ ├── terraform.tfvars
│ └── backend.tf
└── production/
├── main.tf
├── terraform.tfvars
└── backend.tf
Why: Complete isolation, separate state, clear boundaries
Alternative: tfvars Files
code
terraform/
├── main.tf
├── variables.tf
└── environments/
├── staging.tfvars
└── production.tfvars
# Usage
terraform plan -var-file=environments/staging.tfvars
Why: Less duplication when environments are similar
Avoid: Workspaces for Environments
Workspaces share code, making it easy to apply wrong config.
State Management
Remote Backend (Required)
hcl
terraform {
backend "gcs" {
bucket = "my-terraform-state"
prefix = "terraform/state"
}
}
State Safety
- •Enable versioning - Recover from corruption
- •Enable locking - Prevent concurrent modifications
- •Encrypt at rest - State contains secrets
- •Restrict access - IAM for state bucket
- •Never edit manually - Use
terraform statecommands
Handling State Issues
| Issue | Solution |
|---|---|
| Lock stuck | terraform force-unlock <ID> |
| Drift detected | Plan shows unexpected changes |
| Import needed | terraform import <resource> <id> |
| State corruption | Restore from versioned backup |
CI/CD Integration
Pipeline Stages
yaml
stages: - validate # fmt, validate - plan # terraform plan - approve # manual gate (production) - apply # terraform apply
Pre-commit Hooks
yaml
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
hooks:
- id: terraform_fmt
- id: terraform_validate
- id: terraform_tflint
- id: terraform_docs
Critical Rules
- •Never store secrets in tfvars - Use Secret Manager, reference dynamically
- •Lock provider versions - Commit
.terraform.lock.hcl - •Review every plan - Especially destroys
- •Tag module versions -
?ref=v1.2.3 - •Plan in CI - Detect drift early
See reference.md for detailed patterns and examples.md for CI/CD templates.