Infrastructure as Code10 March 20257 min read

Terraform Best Practices for Production — Modules, State Management & CI/CD

Learn the Terraform patterns that separate amateur scripts from production-grade Infrastructure as Code: module design, remote state, Terragrunt, and CI/CD pipeline integration.

RV

Rajesh Vardhan Busam

Cloud Engineer & IaC Specialist

Writing Terraform that works on your laptop is easy. Writing Terraform that a team of engineers can collaborate on safely — across multiple environments and AWS accounts — is a different challenge entirely. These are the patterns that make the difference.

1. Use Remote State (Always)

Never store Terraform state locally in production. Use an S3 backend with DynamoDB locking:

terraform {
  backend "s3" {
    bucket         = "my-company-tfstate"
    key            = "prod/vpc/terraform.tfstate"
    region         = "ap-south-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

The DynamoDB table prevents two engineers from running terraform apply simultaneously, which would corrupt the state file.

2. Structure with Modules

Don't write monolithic Terraform. Break infrastructure into reusable modules:

modules/
  vpc/         → creates VPC, subnets, route tables
  eks/         → creates EKS cluster, node groups
  rds/         → creates RDS instance, parameter groups
environments/
  dev/         → calls modules with dev-specific variables
  staging/
  prod/

Each environment just calls the same modules with different variable values — no code duplication.

3. Pin Provider and Module Versions

Always pin your provider versions. An unpinned hashicorp/aws provider can introduce breaking changes on terraform init:

required_providers {
  aws = {
    source  = "hashicorp/aws"
    version = "~> 5.40"
  }
}

4. Use Terragrunt for Multi-Environment DRY

If you have three environments and five modules, that's 15 backend configurations. Terragrunt eliminates this duplication with a root terragrunt.hcl that generates backend config dynamically for every module.

5. Run Terraform in CI/CD, Not Locally

Production Terraform runs should happen in CI/CD (GitHub Actions, GitLab CI, or Atlantis), never from a developer's laptop. This ensures:

  • Consistent environment (same Terraform version)
  • Audit trail (who applied what, when)
  • Pull request workflow (plan output in PR comment, apply on merge)

6. Validate and Scan Before Apply

Add these steps to your Terraform CI pipeline:

  • terraform fmt -check — enforce consistent formatting
  • terraform validate — catch syntax errors
  • checkov -d . — scan for security misconfigurations
  • terraform plan — review changes before applying

7. Use Workspaces Only for Ephemeral Environments

Terraform workspaces are useful for feature branch environments (spin up, test, destroy). Do not use workspaces for long-lived environments like dev/staging/prod — use separate state files per environment instead.

Our Infrastructure as Code course covers all of these patterns with hands-on AWS labs — building a complete multi-environment Terraform setup with Terragrunt and a full CI/CD pipeline.

Tags

TerraformIaCAWSTerragruntCI/CD