The IaC Operating Model
Scenario: An engineer runs an unreviewed apply from a personal laptop late at night, then leaves the company before anyone else can figure out which code produced the infrastructure now running in production.
Owning the mental model of how Terraform works is only half the job; the other half is how a team safely runs it together, because a single careless apply can affect infrastructure other people depend on right now. A mature workflow separates five distinct steps: authoring (writing the .tf files), review (a human or policy checks the intended change before it happens), planning (Terraform calculates exactly what would change), approval (someone with authority signs off on that specific plan), and application (an authorized, ideally automated, runner executes it).
What goes into version control and what doesn't matters here: commit your .tf configuration files and the dependency lock file (covered in Module 3), but never commit Terraform state or credentials - both can contain secrets and both change with every apply, which would make your Git history an unreadable, sensitive mess.
In a CI/CD pipeline, this typically looks like: format-check the code, initialize deterministically, validate syntax, produce a plan artifact, and have an authorized system - not a random laptop - apply exactly that saved plan.
Analogy: Application code review asks "what behavior will this pull request change?" Infrastructure review asks "what real, billable, potentially customer-facing objects will this change?" Both need one thing in common: an immutable, inspectable artifact that connects what was reviewed to what actually ran - in Terraform, that artifact is the saved plan file.
A worked configuration
terraform fmt -check -recursive
terraform init -input=false
terraform validate
terraform plan -out=change.tfplan
terraform apply change.tfplan
Beyond the basic pipeline shown above, production teams also add concurrency control (so two people can't apply against the same state at once - you'll meet locking in the State module), retain run logs for later audits, restrict who is even allowed to trigger an apply, and design a documented "break glass" procedure for genuine emergencies. None of this is optional ceremony: Terraform is only the execution engine inside this larger socio-technical system, and it cannot compensate for a team that shares one admin credential or merges plans nobody actually read.
Common mistakes in production
- Running
applylocally against shared production state "just this once" - it bypasses every review and audit control the team built, and the next person has no record of what happened or why. - Committing a
.tfvarsfile that happens to contain a real secret because it "only affects dev" - dev secrets get reused, and Git history is forever.
Goal: Never treatterraform apply -auto-approverun from a developer laptop as a substitute for a review-and-approve workflow. Automation exists to strengthen review and identity checks, not to bypass them for convenience. Reinforce this lesson in the tf-saved-plan-replacement Terraform lab. Open/labs/terraformand choose slugtf-saved-plan-replacement; the lab runs real Terraform against the offline FakeCloud provider.