shouclack/tfbp icon
public
Published on 4/24/2025
Terraform Best Practices

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:
```hcl
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.

```hcl
variable "region" {
  type        = string
  description = "AWS region"
  default     = "us-east-1"
}
```

### Outputs

- Only expose necessary values.
- Name outputs clearly.

```hcl
output "vpc_id" {
  value       = aws_vpc.main.id
  description = "The ID of the main VPC"
}
```

---

## 6. Version Pinning

```hcl
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

```hcl
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.