Benefits of Pre-Commit Hooks for Terraform Repos
Your reviewer shouldn't be the one pointing out that a .tf file is misaligned. Pre-commit hooks for Terraform move that conversation to your laptop, where it costs two seconds instead of a review round trip. This article covers what you get from the pre-commit-terraform hook collection, a config you can paste, and the situation where you should stay skeptical.
Set up pre-commit hooks for Terraform
You need pre-commit, git, and Terraform or OpenTofu. Each hook also wraps a tool you install yourself: tflint, terraform-docs (0.12.0 or newer), trivy, and jq if you use the cleanup retry below.
pip install pre-commit
brew install terraform-docs tflint trivy jq
Then add this .pre-commit-config.yaml at the repo root:
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.109.2 # latest at time of writing; run pre-commit autoupdate to bump
hooks:
- id: terraform_fmt
- id: terraform_validate
args:
- --hook-config=--retry-once-with-cleanup=true
- id: terraform_tflint
args:
- --args=--enable-rule=terraform_documented_variables
- id: terraform_docs
args:
- --hook-config=--path-to-file=README.md
- --hook-config=--add-to-existing-file=true
- --hook-config=--create-file-if-not-exist=true
- id: terraform_trivy
args:
- --args=--severity=HIGH,CRITICAL
- --args=--skip-dirs="**/.terraform"
Register the git hook, then sweep the existing code once:
pre-commit install
pre-commit run --all-files
install makes the checks run on every commit. The first --all-files run will probably rewrite a pile of files, so commit that cleanup on its own.
1. Reviews stop being about whitespace
terraform_fmt rewrites configuration to the canonical format, and it covers .tf, .tofu and .tfvars files. Nobody's editor settings can drift anymore, so the diff shows the lines you changed and not a wall of realigned = signs. Reviewers spend their attention on the actual change.
2. Broken configs fail before CI does
terraform_validate catches syntax and reference errors locally. It needs an initialized working directory, and a half-broken .terraform folder is a common cause of confusing failures. The --retry-once-with-cleanup=true flag in the config above deletes .terraform/modules/ and .terraform/providers/ on failure and retries once.
terraform_tflint goes further than validate. The README example enables terraform_documented_variables, and you can add provider rulesets through a .tflint.hcl file. If that file declares plugins, run tflint --init once so they are installed.
3. Module docs stay current
terraform_docs writes the inputs and outputs table between two markers in your README:
# network-module
<!-- BEGIN_TF_DOCS -->
<!-- END_TF_DOCS -->
Change a variable and the table updates in the same commit. When a hook edits a file, pre-commit fails that commit, so stage the change and commit again. Nobody has to remember to update the docs because the commit does it.
4. Security findings arrive before the push
terraform_trivy runs trivy conf with --exit-code=1, so a finding that survives your filters fails the commit. Your --args pass straight through to Trivy, which is how the severity filter above works. It also replaces the deprecated terraform_tfsec hook, so it is the one to use on new setups. A public bucket caught on your laptop never becomes a comment from the security team.
5. One config for Terraform and OpenTofu
The hooks find the binary in this order: the per-hook --hook-config=--tf-path, then the PCT_TFPATH environment variable, then TERRAGRUNT_TFPATH, then terraform on your PATH, then tofu. If only OpenTofu is installed, it just works. To force it:
- id: terraform_validate
args:
- --hook-config=--tf-path=tofu
The same effect comes from export PCT_TFPATH=tofu in your shell.
When pre-commit hooks for Terraform aren't worth it
In a large monorepo, the validate and Trivy hooks can make every commit feel slow. Validation needs an initialized directory, and re-initializing can mean downloading providers and modules. The framework works per directory, so a commit that touches many modules pays for all of them.
You have three ways out. Scope hooks with a files: regex, as the README does for Trivy with files: ^prd-infra/. Skip one heavy hook for a single commit with SKIP=terraform_validate git commit -m "...". Or let CI own the slow checks.
The bigger caveat is that git commit --no-verify skips every hook. Treat local hooks as a convenience and CI as the gate: run pre-commit run --all-files as a required CI job, so a skipped hook still gets caught before merge.
Gotchas
- Install the wrapped tools (
tflint,terraform-docs,trivy,jq) on every developer machine and in CI, or the hooks fail with missing-binary errors. - Pin
revto a release tag and bump it deliberately withpre-commit autoupdate. terraform_docsneeds the markers in the README, or the--add-to-existing-fileand--create-file-if-not-existoptions to add them.- Hooks that modify files make the commit fail the first time. That is normal: stage the changes and commit again.
For anyone shipping infrastructure under AI workloads, these checks catch formatting, lint, documentation and security problems at commit time, while the fix is still cheap.