Terraform Best Practices
This skill ensures that Terraform configurations are modular, secure, and maintainable by following established industry standards and organizational patterns.
When to Use
- Reviewing existing Terraform code for anti-patterns and technical debt.
- Refactoring monolithic
.tffiles into reusable, versioned modules. - Setting up new infrastructure projects to ensure a consistent directory structure from the start.
- Validating security, naming conventions, and resource tagging before committing changes.
Core Guidelines
1. Standard Directory Structure
Every module or root configuration MUST maintain a consistent file layout:
main.tf: Primary resource definitions.variables.tf: Input variable declarations (always includedescriptionandtype).outputs.tf: Output value definitions (always includedescription).versions.tf: Minimum required Terraform and provider version constraints.providers.tf: Provider configurations (restrict this to root modules only).
2. The Module Pattern
- Encapsulate: Move complex or repetitive logic into a local
modules/directory or a remote registry. - Root Simplicity: Root modules should primarily serve as an orchestration layer, calling sub-modules.
- Decouple: Avoid hardcoding environment-specific values; pass them as variables.
3. State Management
- Remote Backends: Always use a remote backend (e.g., S3 + DynamoDB for AWS, GCS for GCP) for team collaboration.
- State Locking: Ensure state locking is enabled to prevent concurrent modifications and state corruption.
4. Semantic Versioning (SemVer)
All separated or shared modules MUST follow semantic versioning (MAJOR.MINOR.PATCH) based on the interface (variables and outputs):
- MAJOR (Breaking): Incremented for breaking changes to the module's interface (e.g., removing a variable, changing a variable type, or changing the resource graph in a way that requires recreation).
- MINOR (Feature): Incremented for new features that are backwards-compatible (e.g., adding a new optional variable or a new output).
- PATCH (Fix): Incremented for backwards-compatible bug fixes or internal refactors that do not change the interface.
- Requirement: Every version bump MUST be accompanied by successful Terratest execution.
5. Naming & Tagging Conventions
- Naming: Use
snake_casefor all resource, variable, and output names. Avoid repeating the resource type in the name (e.g., useresource "aws_instance" "web" {}instead ofweb_instance). - Standard Tagging: Taggable resources MUST include a standard
tagsblock:Owner: The team or individual responsible for the resource.Environment: Deployment stage (e.g.,dev,staging,prod).Project: Name of the project or application.ManagedBy: Always set toterraform.
5. Validation & Tooling
Before finalizing changes, execute the following sequence:
- Format:
terraform fmt(automated style alignment). - Validate:
terraform validate(syntactic and structural check). - Lint: Use
tflintfor deep linting and provider-specific best practices. - Security: Run
tfsecorcheckovto identify security vulnerabilities. - Test: Execute automated infrastructure tests using Terratest to verify behavioral correctness.
Infrastructure Testing (Terratest)
Every module MUST include automated tests in a tests/ directory:
- Language: Use Go with the
gruntwork-io/terratestlibrary. - Scope:
- Unit Tests: Deploy a minimal version of the module and verify outputs/resource attributes.
- Integration Tests: Verify the module works correctly when combined with other infrastructure (e.g., VPC + DB).
- Cleanup: Always use
defer terraform.Destroy(t, terraformOptions)to ensure resources are cleaned up after tests.
Workflow: Reviewing Existing Code
- Inventory: Identify all
.tffiles and their dependencies. - Gap Analysis: Compare the current layout and code against these best practices.
- Detection: Look for anti-patterns:
- Missing
descriptionon variables/outputs. - Hardcoded secrets or sensitive data (recommend
vaultoraws_secretsmanager). - Monolithic files (> 300 lines).
- Missing
- Refactor Plan: Propose a step-by-step plan to modularize or fix the identified issues.
Workflow: Authoring New Resources
- Scaffold: Create the standard file set (
main.tf,variables.tf, etc.). - Define: Declare variables with clear types and descriptions before writing resource blocks.
- Document: Use
terraform-docsto generate READMEs for modules.
Overriding Standards (TERRAFORM.md)
If a TERRAFORM.md file exists in the workspace root, its instructions and conventions take absolute precedence over these general guidelines. Always check for this file first.