Top 7 Terraform Gotchas (and How to Avoid Them)

Terraform has become the go-to Infrastructure as Code (IaC) tool for DevOps engineers, and for good reason. It’s declarative, cloud-agnostic, and integrates well into CI/CD workflows. But anyone who’s worked with it long enough knows: Terraform can bite you when you least expect it.

1. State File Mismanagement

What Happens:
The Terraform state file tracks the current status of your infrastructure. If it’s lost, corrupted, or not managed properly, you risk inconsistencies—or worse, complete infra recreation.

Avoid It:

  • Always use remote state backends like AWS S3 with locking via DynamoDB.
  • Encrypt state at rest and in transit.
  • Enable versioning for recovery.

2. create_before_destroy and prevent_destroy Misuse

What Happens:
Terraform might destroy a resource before creating a replacement. This could mean downtime, lost data, or broken dependencies.

Avoid It:

  • Use create_before_destroy = true in lifecycle blocks for resources like load balancers and DNS records.
  • Add prevent_destroy = true on critical infrastructure components like databases and S3 buckets.
hclCopyEditlifecycle {
  create_before_destroy = true
  prevent_destroy       = true
}

3. Misusing count or for_each

What Happens:
Changing the order or logic behind count can lead to recreation of resources, even when unnecessary.

Avoid It:

  • Prefer for_each when dealing with key-based maps to retain resource identity.
  • Never tie count values to external resources that might fluctuate unexpectedly.

4. Dynamic Blocks Confusion

What Happens:
Dynamic blocks are great for conditional logic, but when misused, they create confusing configs and unexpected diffs.

Avoid It:

  • Keep dynamic blocks minimal and readable.
  • Test with terraform plan frequently.
  • Use locals for complex expressions to avoid repetition.

5. Provider Version Drift

What Happens:
If you don’t lock your provider versions, newer releases might introduce breaking changes or deprecations without warning.

Avoid It:

  • Pin provider versions in your Terraform configuration:
hclCopyEditterraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

6. Insecure Secrets Handling

What Happens:
Hardcoding secrets in .tf files or using variables without care can expose sensitive credentials.

Avoid It:

  • Use environment variables or secret managers (e.g., AWS Secrets Manager, Vault).
  • Never commit .tfstate or .terraform folders to version control.
  • Redact outputs with sensitive = true.
hclCopyEditoutput "db_password" {
  value     = var.db_password
  sensitive = true
}

7. Ignoring Infrastructure Drift

What Happens:
Manual changes to infra outside of Terraform create drift—Terraform thinks your infra is in one state, but reality says otherwise.

Avoid It:

  • Schedule regular terraform plan and drift detection in CI/CD.
  • Use tools like Infracost and Driftctl to analyze state vs reality.
  • Train teams to follow a “no manual changes” policy.

Terraform is powerful—but with great power comes great responsibility (and the occasional panic moment).

By understanding these gotchas and implementing guardrails, you’ll save yourself from headaches, minimize downtime, and make your IaC truly reliable.