What fmt does
terraform fmt is gofmt for HCL. It does not change what your code
means, only how it looks: consistent indentation (two spaces),
aligned = signs in argument blocks, collapsed blank lines,
uniform quotes.
The goal is to remove style debates from code review, so diffs in PRs stay focused on logic, not whitespace.
Basic usage
Without flags, it formats all .tf and .tfvars files in the current
directory and writes the changes to disk:
cd ~/myproject
terraform fmt
The output is a list of changed files:
main.tf
variables.tf
If nothing is printed, all files were already formatted.
Recursive mode
By default fmt looks only at the current directory. To traverse
all subdirectories:
terraform fmt -recursive
You need this in repositories that contain modules (modules/vpc/, modules/alb/): without -recursive those directories are skipped.
What fmt does to HCL
Before:
resource "aws_s3_bucket" "demo" {bucket="my-bucket"
tags={Owner="student"
Env ="dev"
}
}
After terraform fmt:
resource "aws_s3_bucket" "demo" {bucket = "my-bucket"
tags = {Owner = "student"
Env = "dev"
}
}
Notice that Owner and Env are now aligned on =. That alignment is automatic, not manual work.
CI modes
Locally you want fmt to fix files. In CI you want it to fail the
build when someone commits unformatted code.
# fail with a non-zero exit code if anything is unformatted
terraform fmt -check -recursive
# same thing, plus show a diff of what is wrong
terraform fmt -check -diff -recursive
Flags:
-check: do not write to disk; exit 0 means everything is fine, exit 3 means there are unformatted files.-diff: show a line-by-line diff.-write=false: synonym for "do not write"; rarely used on its own.
Pre-commit hook
The most practical use is to add fmt to a pre-commit hook so
unformatted code never reaches git at all:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.88.0
hooks:
- id: terraform_fmt
With this in place, git commit formats tf files before the commit
goes through. If a bad style ever makes it into the repository, it
was a deliberate attempt to bypass the hook, not a case of forgetting
to run fmt.
What fmt does NOT do
- It does not check syntax. Broken HCL is not something fmt can fix. Use tf-validate for that.
- It does not rename identifiers.
Resourceinstead ofresourceis an error, not a style issue.validatecatches it. - It does not sort arguments alphabetically. The order of arguments inside a block is preserved.
- It does not touch comments. If your code has
# A note here, it stays where it is. - It does not work with .tf.json. HCL only.
Pitfalls
fmtwrites to disk by default. If a colleague has a file open in an editor with unsaved changes and you runfmt, those changes can be lost. In a team setup, IDE integration is safer (the Terraform extension for VS Code and JetBrains calls fmt automatically).fmt -recursivealso enters.terraform/. That directory is usually in.gitignore, so there are no practical consequences, but fmt will still look inside it.- The Terraform version matters. Formatting rules can change between
minor releases (for example, 1.9 added comment alignment). The team
should use the same version, otherwise PRs with "fmt-only" changes
will keep appearing. Fix this with
.terraform-version(for tfenv) or a pinned version in CI. - Do not run
fmtin CI without-check. Otherwise CI will rewrite files and commit them itself, and the commit owner is ambiguous. Fix formatting locally; CI is for checking only.