# pre-commit-terraform: Terraform, OpenTofu and Terragrunt checks that run on git commit

> pre-commit-terraform is a collection of git hooks for the pre-commit framework that format, validate and lint Terraform, OpenTofu and Terragrunt code before a commit lands. It is the right tool when your team already uses pre-commit and wants the same checks locally and in CI; it is the wrong tool if you want a single binary with no Python or Docker in the loop.

**antonbabenko/pre-commit-terraform** — pre-commit git hooks to take care of Terraform configurations 🇺🇦

- Repository: https://github.com/antonbabenko/pre-commit-terraform
- Stars: 3,782 · Forks: 586
- Language: Shell
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/antonbabenko-pre-commit-terraform

## The problem: Terraform style drift between commit and CI

Terraform configuration rots in small ways. A provider block gets reformatted by one editor and not another. A variable is added without a description. A module README stops matching its inputs. Each of these is cheap to fix at commit time and expensive to fix in a pull request that has already been reviewed.

pre-commit-terraform targets that gap. It is a collection of git hooks for Terraform, OpenTofu and Terragrunt that plug into the pre-commit framework, so the checks run on the developer's machine before the commit object is written. The README describes the goal plainly: keeping configurations "in good shape by automatically running various checks and formatting code before committing changes".

The audience is narrow and specific. You need to be using git, you need the pre-commit framework, and your infrastructure code needs to be Terraform, OpenTofu or Terragrunt. Teams that use Terraform Cloud's native run triggers, or that lint only in CI, get nothing from this project.

## How the hooks fit together: pre-commit drives, the tools do the work

The architecture is a thin shell layer, not a linter. The repository is mostly Shell with a Python packaging layer (pyproject.toml declares the project, requires Python 3.10 or newer, and pulls in no runtime dependencies). The real work is delegated: the hooks call out to terraform, tflint, terraform-docs, trivy, checkov, infracost, terrascan, tfupdate and hcledit, each installed separately.

That split explains most of the behaviour. Because the hooks are wrappers, a hook can only run as well as the binary it wraps, and version drift between a developer's terraform and the CI runner's terraform becomes a real source of "works on my machine" failures. It also explains the breadth: adding a new tool is a matter of writing a wrapper, not reimplementing a linter.

The README lists the hooks by name: terraform_fmt, terraform_validate, terraform_docs, terraform_tflint, terraform_trivy, terraform_providers_lock, terraform_wrapper_module_for_each, terragrunt_providers_lock, terragrunt_validate, terragrunt_validate_inputs, infracost_breakdown, tfupdate and terrascan. Several older entries carry a deprecation note in the same list: checkov, terraform_tfsec and terraform_docs_replace. The README points users of checkov to terraform_checkov and of tfsec to terraform_trivy, which is a migration signal rather than a removal, but it means new configurations should not start on the deprecated names.

Scope control is handled by the framework, not by the project. The README states the hooks can run for the entire repository or only for change-related files, such as a local git stash, the last commit, or all changes in a pull request. That is what keeps a large monorepo from paying for a full scan on every commit.

## Installing pre-commit-terraform and running terraform_fmt for the first time

The README's install path has four steps: install dependencies, install the pre-commit hook globally, add configs and hooks, then run. Two dependency routes are documented. The Docker route pulls a prebuilt image that already contains the tools:

```bash
TAG=latest
docker pull ghcr.io/antonbabenko/pre-commit-terraform:$TAG
```

The README also documents building the image yourself, which it recommends reading about first: the section on Docker image security explains why you may prefer to build and maintain your own image rather than trust the published one. When no hook-related build arguments are given, the image installs only the latest pre-commit and terraform.

```bash
git clone git@github.com:antonbabenko/pre-commit-terraform.git
cd pre-commit-terraform
docker build -t pre-commit-terraform --build-arg INSTALL_ALL=true .
```

The Dockerfile shows how the per-tool arguments work. Each tool has its own build argument, for example TERRAFORM_VERSION, TFLINT_VERSION, TERRAFORM_DOCS_VERSION, TERRAGRUNT_VERSION, TRIVY_VERSION and CHECKOV_VERSION, all defaulting to false. Setting INSTALL_ALL to anything other than false writes latest into the environment file that the build sources, which is how one argument installs everything. The README notes that building requires docker buildx as the default builder, or TARGETOS and TARGETARCH passed as additional build arguments.

The non-Docker route is the pre-commit framework itself. Add a .pre-commit-config.yaml at the repository root, reference the hooks repository, and pick the hook ids you want. The README's available-hooks list is the source of the ids; the framework fetches the hook definitions from the repository's .pre-commit-hooks.yaml. After the config exists, the README's fourth step is to run the framework, which is what executes the hooks against your files. Because the hook names in the README are the ids you put in the config, a minimal setup enables terraform_fmt and terraform_validate and nothing else.

Before any of this, the tools must exist on PATH. The hooks shell out, so a config that enables terraform_docs will fail on a machine without terraform-docs installed, and the failure will read as a hook failure rather than a missing binary unless you read the log.

## Where pre-commit-terraform breaks down

The dependency model is the main limitation, and it is structural. The README's install section is titled "Install dependencies" for a reason: this project does not ship terraform, tflint, terraform-docs, trivy or terragrunt. Every hook you enable is a promise that the corresponding binary is present and roughly the version you expect. In a team with heterogeneous machines, that promise is the thing that fails, and it fails at commit time, which is the worst moment for a slow or confusing error.

The Docker image addresses the binary problem by freezing a set of tools, but it introduces its own constraint. The README devotes a section to Docker image security and explicitly says you probably want to build and maintain your own image, which is a maintenance task in itself. The image also carries file permission and tool cache concerns, both documented as their own sections, and a section on downloading Terraform modules from private GitHub repositories, which tells you the container needs credentials configured before it can do everything the local hooks can.

There is also a version-pinning tension. The README documents pinning a specific tool version for most hooks and points at Renovate for keeping those pins current. Pinning is correct for reproducibility, but it means the pins are now something a human has to review, and a stale pin silently holds the whole team on an old tflint or terraform-docs.

Finally, consider when this is the wrong tool. If your team does not use the pre-commit framework and has no intention of adopting it, this project adds a Python dependency and a config file to solve a problem a CI-only pipeline already solves. If your Terraform runs are driven entirely through a platform that enforces policy server-side, client-side hooks are a duplicate control. And if your repository is small enough that a full lint takes seconds in CI, the local hook buys convenience rather than correctness.

## pre-commit-terraform versus running tflint and terraform fmt directly in CI

The obvious alternative is to skip the framework and call the tools yourself in a CI job: run terraform fmt -check, tflint, terraform validate and terraform-docs in a pipeline step. That approach has one real advantage, which is that it has no local installation surface at all. Nothing to install on a laptop, no Python version floor, no hook definitions to keep in sync.

The difference in approach is where the feedback arrives. Direct CI calls catch problems after the push, on a machine you control, with a single toolchain version. pre-commit-terraform catches them before the commit exists, on a machine you do not control, with whatever toolchain the developer happens to have. The project's answer to that second half is the Docker image and the documented version pinning; the direct-CI approach's answer is to not have the problem.

There is a middle path the README itself supports: the hooks can run in CI as well as locally, and they can be limited to changed files. That gives you one config file describing the checks and two execution points, which is the actual argument for adopting the framework rather than scripting the tools. You are buying a single source of truth for hook definitions, not a better linter.

## Maintenance, releases and the MIT licence

The project is not archived, and the last push was on 2026-09-22. Releases are frequent and versioned: v1.109.1 on 2026-09-04, v1.109.0 on 2026-08-21, and v1.108.1 on 2026-07-24. That cadence matters for a hooks project, because the tools it wraps release on their own schedules and the wrappers have to keep up.

Upgrade cost is mostly config review. Because hooks are pinned by revision in .pre-commit-config.yaml, moving forward is a deliberate edit, and the README's Renovate section exists precisely because manual pin updates do not happen on their own. Expect to read the changelog when a hook you depend on changes its arguments, and expect to re-check your tool versions when a wrapper starts requiring a newer binary.

The licence is MIT, declared in the repository's LICENSE file and in the pyproject.toml classifier ("License :: OSI Approved :: MIT License"). MIT is permissive: you can use, modify and redistribute the hooks, including inside a company, provided the copyright notice and permission notice are preserved. That is a statement about the licence text, not legal advice; if you are vendoring the code into a product, have your own counsel read the file.

The README also carries an additional-information note for users from Russia and Belarus, and a StandWithUkraine banner. That is a project-level position, not a licence term, but it is visible on the repository and worth knowing before you propose the dependency internally.

## Conclusion

Adopt pre-commit-terraform if your team already runs the pre-commit framework and wants terraform_fmt, terraform_validate and terraform_docs enforced at commit time and again in CI from one config file. Do not adopt it if you cannot install Python 3.10 or newer on developer machines and have no appetite for the Docker image. Before rolling it out, verify that each hook you enable has its underlying binary available, because the hooks shell out to terraform, tflint, terraform-docs and the rest rather than bundling them.

## FAQ

### How do I install pre-commit-terraform?

The README documents two routes. You can pull the prebuilt Docker image ghcr.io/antonbabenko/pre-commit-terraform, or you can install the pre-commit framework, add a .pre-commit-config.yaml referencing the hooks repository, and let the framework fetch the hook definitions. The README's install section also lists installing the underlying tools as step one.

### How do I use pre-commit-terraform?

Add a .pre-commit-config.yaml at the repository root, reference the hooks repository, and enable the hook ids you want from the available-hooks list, such as terraform_fmt or terraform_validate. The hooks then run through the pre-commit framework, either for the whole repository or only for change-related files.

### What does pre-commit mean in pre-commit-terraform?

It refers to the pre-commit framework, which this project is driven by, and to the git hook stage where the checks run. The README describes the project as a collection of git hooks for Terraform and related tools that run before changes are committed to version control.

### How do I install the pre-commit framework that pre-commit-terraform needs?

The README lists installing the pre-commit hook globally as its second install step, after dependencies. The Docker route sidesteps this: when no hook-related build arguments are given, the Dockerfile installs the latest version of pre-commit and terraform in the image.

## Sources

- [antonbabenko/pre-commit-terraform on GitHub](https://github.com/antonbabenko/pre-commit-terraform)
- [Issues](https://github.com/antonbabenko/pre-commit-terraform/issues)
- [License: MIT](https://github.com/antonbabenko/pre-commit-terraform/blob/master/LICENSE)
- [README](https://github.com/antonbabenko/pre-commit-terraform/blob/master/README.md)
- [Releases](https://github.com/antonbabenko/pre-commit-terraform/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/antonbabenko-pre-commit-terraform
