shouclack/tfbp icon
public
Published on 4/24/2025
shouclack/tfbp

Describe best Terraform pratices

Rules

Terraform Coding Best Practices

1. General Principles

  • Idempotency: Write code that produces the same result every time it is applied.
  • Declarative, not imperative: Let Terraform handle the "how." Describe the desired state.
  • Environment agnostic: Make code reusable across environments via variables and workspaces.

2. File and Project Structure

/terraform
  /modules
    /<module_name>
      - main.tf
      - variables.tf
      - outputs.tf
  /envs
    /dev
    /prod
      - main.tf
      - backend.tf
      - variables.tf
      - terraform.tfvars
  - versions.tf
  - provider.tf
  - README.md
  • Use logical separation (e.g., environments vs modules).
  • Use backend.tf for remote state configuration.
  • Use terraform.tfvars files for environment-specific values.

3. Naming Conventions

  • Use snake_case for resources and variables.
  • Prefix resources with their context (e.g., vpc_prod_main).
  • Name modules descriptively: network, compute, iam.

Example:

resource "aws_instance" "web_prod_app1" {
  ...
}

4. Modules

  • Write small, focused modules (single purpose).
  • Always use versioned modules when using external sources.
  • Include:
    • main.tf (resources)
    • variables.tf (inputs)
    • outputs.tf (exposed values)
  • Do not hardcode values; always use variables.

5. Variables and Outputs

Variables

  • Provide type, description, and defaults.
  • Use validation blocks where applicable.
variable "region" {
  type        = string
  description = "AWS region"
  default     = "us-east-1"
}

Outputs

  • Only expose necessary values.
  • Name outputs clearly.
output "vpc_id" {
  value       = aws_vpc.main.id
  description = "The ID of the main VPC"
}

6. Version Pinning

terraform {
  required_version = ">= 1.6.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
  • Pin Terraform and provider versions to avoid drift and breakage.

7. Security Best Practices

  • Use remote backends with locking (e.g., S3 + DynamoDB for AWS).
  • Use data sources to fetch existing values instead of hardcoding.
  • Never commit secrets or state files to Git.
  • Use environment variables or secret managers for sensitive data.

8. State Management

  • Use remote state with proper locking and encryption.
  • Use state file separation per environment.
  • Use terraform state commands to move or inspect resources.

9. Linting, Validation, and Testing

  • Use terraform fmt to standardize formatting.
  • Use terraform validate before applying.
  • Integrate tflint, checkov, and terrascan for static analysis.
  • Use automated tests with tools like terratest or kitchen-terraform.

10. CI/CD Integration

  • Use pipelines to:
    • Lint and validate
    • Plan with -out option
    • Enforce manual approval before apply
  • Store terraform plan output as artifacts.

11. Documentation

  • Include README in each module with:
    • Purpose
    • Inputs/Outputs
    • Usage examples
  • Document resource changes and module versions.

12. Git Best Practices

  • Use feature branches and pull requests.
  • Include plan output in PR description.
  • Tag releases for module versions.
  • Use .terraform.lock.hcl to ensure deterministic builds.

13. Clean Code Tips for LLMs

  • Use clear, consistent indentation and spacing.
  • Comment why, not just what.
  • Break large resource definitions into logical parts.
  • Favor readability over cleverness.

14. Bonus: AI-Friendly Formatting

  • Use consistent patterns that make code easily parseable.
  • Avoid dynamic code generation unless well-justified.
  • Use descriptive variable and output names.

Example: Clean, Modular Terraform Usage

module "vpc" {
  source = "../modules/vpc"

  name   = "prod-vpc"
  cidr   = "10.0.0.0/16"
  region = var.region
}

output "vpc_id" {
  value       = module.vpc.vpc_id
  description = "The ID of the VPC"
}

Summary

These best practices aim to ensure:

  • Readable, maintainable code
  • Safe and secure deployments
  • AI-generatable, modular, and robust infrastructure

Always test your code. Always document your intent.