Formatting Terraform code, updating documentation, and checking configuration are repeatable chores. A Make target gives each task a name in a project-root makefile: run `make test` to execute the commands assigned to `test`. Targets can also depend on other targets, letting one command run a shared workflow. section 7.2.2 section 7.6
Listing 7.5 Using the makefile
.PHONY: chores chores: format document #1 .PHONY: format format: terraform fmt #2 .PHONY: document document: terraform-docs -c .terraform-docs.yml . #3
The `chores` target depends on `format` and `document`. Running `make chores` invokes the targets that run `terraform fmt` and `terraform-docs`. This keeps the developer-facing command short while leaving the individual tasks available separately. section 7.2.2
Use `.PHONY` for a target whose commands do not create a corresponding file: Make will run it each time it is invoked. Leave `.PHONY` off a target that represents a real file or directory; if that output already exists, Make can skip its command. Commands under a target must be indented with tabs, not spaces. A makefile variable can hold a command name and be overridden when needed. section 7.2.2 section 7.3.1
Listing 7.15 terraform validate makefile
.terraform: #1
$(TF_BINARY) init -backend=false #2
.PHONY: test_validation
test_validation: .terraform #3
$(TF_BINARY) validate
Here `.terraform` represents the directory created by initialization. `test_validation` depends on it, so initialization runs when the directory is absent; an existing directory avoids repeating that step. `-backend=false` preserves a developer’s previously configured backend, while `TF_BINARY` allows the validation workflow to use Terraform or OpenTofu. section 7.3.1
For a shared entry point, a high-level `chores` target can depend on documentation and formatting targets, so developers run `make chores`. Avoid defining the same target twice: Make warns about duplicates. Named targets also make the commands easier to reuse in CI pipelines. section 7.6 section 7.3.1
