Core Terraform workflow Study Guide — 004

13% of the exam · domain 3 of 8 · HashiCorp Terraform Associate · Free Core Terraform workflow practice questions

0 of 41 topics covered
What the exam asks here — tap to tick off0 / 7 covered
Domain 3 of 8

Core Terraform workflow

This domain covers the day-to-day command sequence every Terraform practitioner runs: write → plan → apply, plus the supporting commands terraform init, terraform validate, terraform fmt, and terraform destroy. HashiCorp does not publish per-objective weightings; the ~13% figure used here is an even split across the exam's objective groups, and the commonly cited "57 questions / 70% to pass / 60 minutes" numbers are carried over from version 003 and should be treated as estimates. Regardless of weighting, this is the highest-yield domain on the exam: command flags, plan symbols, and "which command do I run next?" scenarios appear throughout the other domains too. Expect precise questions about exact flag names, defaults, exit codes, what each command does and does not do, and when re-initialization is required.


Describe the Terraform workflow: write, plan, apply

The core Terraform workflow has exactly three steps:

StepWhat happensPrimary commands
WriteAuthor configuration in HCL files (.tf, .tf.json), iterating locallyeditor, terraform fmt, terraform validate
PlanTerraform reads state, refreshes real-world status, and computes the diff between desired and current stateterraform plan
ApplyTerraform executes the planned actions against provider APIs in dependency order and writes new stateterraform apply

terraform init is a prerequisite/setup step, not one of the three core steps. terraform destroy is the teardown of the lifecycle, not a core workflow step. The exam loves the distractor "write, init, plan, apply" — reject it when the question asks for the core workflow.

How the same workflow scales:

ContextWritePlanApply
IndividualLocal files, no VCS coordination requiredRun terraform plan locally, inspect outputterraform apply locally, type yes
TeamFiles in version control, feature branches, pull requestsPlan output pasted into PR for peer review; state stored in a shared remote backend with lockingApply after merge, ideally from one place to avoid concurrent runs
HCP Terraform / Terraform EnterpriseVCS-connected workspaceSpeculative plans on PRs, remote plan execution, policy checks (Sentinel/OPA)Remote apply with mandatory confirmation or auto-apply; state stored and versioned remotely

Caption: the full command lifecycle, with the three core workflow steps highlighted in sequence.

Common traps

  • Calling init part of the core workflow. The core workflow is write, plan, apply only.
  • Assuming plan changes infrastructure. Plan is read-only against infrastructure — it never creates, modifies, or deletes real resources (it may update state metadata only when you explicitly use -refresh-only on apply).
  • Assuming apply always runs a plan. It does — unless you hand it a saved plan file, in which case it executes that plan verbatim.
  • Thinking a speculative plan in HCP Terraform can apply. Speculative plans cannot be applied; they are plan-only.
  • Confusing "the core workflow" with "the enterprise workflow." The steps are identical; only where they run and who reviews them changes.

Initialize a Terraform working directory

terraform init prepares a working directory for use. It is safe to run multiple times (idempotent) and is the first command you run in a new or cloned configuration.

What init does, in order:

  1. Backend initialization — reads the backend/cloud block, configures state storage, and offers to migrate existing state if the backend changed.
  2. Module installation — downloads/copies every module source into .terraform/modules/ and writes modules.json.
  3. Provider plugin installation — resolves version constraints, downloads plugins from the Terraform Registry (registry.terraform.io by default) into .terraform/providers/.
  4. Dependency lock file — creates or updates .terraform.lock.hcl in the working directory with selected provider versions and checksums.

The .terraform directory:

PathContents
.terraform/providers/<host>/<namespace>/<type>/<version>/<os_arch>/Provider plugin binaries
.terraform/modules/Downloaded module sources plus modules.json manifest
.terraform/terraform.tfstateBackend configuration cache (not your resource state when using a remote backend)
.terraform/environmentName of the currently selected workspace
.terraform.lock.hclOutside .terraform — provider dependency lock; commit this to version control

.terraform/ is machine-local and belongs in .gitignore. .terraform.lock.hcl must be committed so teammates and CI get identical provider versions.

Key init flags:

FlagEffect
-backend=falseSkip backend initialization (useful when you only want plugins)
-backend-config=PATH or -backend-config="k=v"Supply partial backend configuration (secrets, per-environment values)
-reconfigureReinitialize, ignoring existing backend state; does not migrate state
-migrate-stateReinitialize and copy existing state to the newly configured backend
-force-copyLike -migrate-state but auto-answers "yes" to migration prompts
-upgradeRe-resolve providers/modules to the newest versions allowed by constraints and update the lock file
-get=falseSkip module downloads
-plugin-dir=PATHUse only plugins from a local directory (disables registry downloads)
-lockfile=readonlyFail rather than update .terraform.lock.hcl
-input=falseNever prompt — standard in automation
-from-module=SOURCECopy a module's source into the current empty directory, then init

When do you need to re-run init?

ChangeRe-init required?
Added a new provider / new resource type from a new providerYes
Changed a provider version constraintYes (with -upgrade if loosening to a newer version)
Added, removed, or changed a module source or versionYes
Changed the backend/cloud blockYes (-reconfigure or -migrate-state)
Cloned a repo to a new machine or fresh CI runnerYes
Changed a resource argument, variable, or outputNo
Switched workspace with terraform workspace selectNo

Caption: decision tree for choosing the right terraform init flag.

Worked scenario: A team has been running Terraform with local state. They add an s3 backend block and rerun terraform init. Terraform detects the backend change and prompts to copy existing state. They want the existing resources preserved in S3 but must run non-interactively in CI. Reasoning: Preserving state = migration, so -reconfigure is wrong (it would discard the association and leave local state behind). Non-interactive migration = terraform init -migrate-state -force-copy (or -migrate-state -input=false with -force-copy). Answer: -migrate-state, with -force-copy to suppress the prompt.

Common traps

  • Believing init downloads providers into a global directory by default. They go into the working directory's .terraform/providers/ unless TF_PLUGIN_CACHE_DIR or a filesystem mirror is configured.
  • Confusing -reconfigure with -migrate-state. -reconfigure discards the old backend association without migrating state.
  • Thinking -upgrade ignores version constraints. It upgrades only within the constraints in required_providers.
  • Thinking .terraform.lock.hcl should be gitignored. It should be committed; .terraform/ should not.
  • Thinking terraform get is a substitute for init. terraform get installs modules only — no backend, no providers, no lock file.
  • Assuming init validates configuration correctness. It parses enough to resolve providers/modules but is not a substitute for validate.
  • Believing running init twice is destructive. It is safe and idempotent.

Unlock with a paid plan

8 more sections (about 3,005 words) continue below. Every paid plan unlocks all 004 study guides, the full question bank and mock exams, from $4.97/month.