Online Tool Store Online Tool Store
🏗️ Developer Tools

· 5 min read

How to Format Terraform the Canonical Way

Manesh Jayawardhana

CIO & Co-founder

Manesh Jayawardhana is the CIO and Co-Founder of Ceyentra Technologies, where he has spent over nine years leading the design and delivery of software solutions for clients across the globe, spanning web, mobile, AI, and capital market systems. He has grown Online Tool Store's engineering team from the ground up while steering the company's technical direction. His writing draws on this breadth of experience building and shipping software across a wide range of industries and markets. View on LinkedIn

Share

How to Format Terraform the Canonical Way

A Terraform pull request shows forty changed lines. Thirty-six of them are whitespace, because someone’s editor reindented the file and the equals signs shifted. Finding the four lines that change infrastructure means reading all forty.

HCL has a canonical format precisely so this does not happen, and it is enforceable in one line of CI.

What canonical formatting does

Two rules produce most of the effect.

Two-space indentation for each nesting level.

Aligned assignments within each group of consecutive arguments. The equals signs line up, which makes a block scannable at a glance.

The alignment detail people miss is that it resets at a blank line or a nested block. A resource with three arguments, a blank line, then four more has two independent alignment groups, each aligned within itself. That is why a long block can have equals signs at several different columns and still be correctly formatted.

Understanding that rule is the difference between trusting the formatter and fighting it.

Why it matters more in infrastructure code

Formatting churn is annoying in application code. In infrastructure code it is a review hazard.

A Terraform diff is the thing standing between a plan and production. When a review has to distinguish four real changes from thirty-six cosmetic ones, the probability of missing one rises — and the missed one might be a security group rule or a deletion protection flag.

Consistent formatting is not tidiness here. It is what keeps the diff readable enough to review properly.

PracticeEffect on review
Formatted on commitDiff shows only real changes
Formatted occasionallyPeriodic whole-file churn
Never formattedEvery diff mixes both
terraform fmt -check in CIUnformatted code cannot merge

Where to enforce it

Pre-commit hook — catches it before the code leaves the machine, which is the cheapest place.

CI checkterraform fmt -check -recursive fails the build on unformatted files. This is the one that actually guarantees the repository stays formatted, because it does not depend on anyone having installed the hook.

Editor on save — convenient and per-developer, so it supplements the other two rather than replacing them.

Formatting is also worth separating from any other change. A commit that reformats and modifies infrastructure in one go is a commit nobody can review.

Formatting is not the same as linting

Two different jobs, frequently conflated.

Formatting fixes layout — indentation, alignment, line breaks. It has one correct output and no opinions about content.

Linting enforces conventions — naming patterns, required tags, deprecated arguments, provider version constraints, modules pinned to specific versions. Tools like tflint and Checkov cover this ground, and the rules are yours to choose.

A repository with formatting enforced and no linting has consistent whitespace and inconsistent everything else. Resource naming drifts, tags are missed on half the resources, and security misconfigurations pass review because nobody was looking for them specifically.

Both belong in CI, and they catch entirely different classes of problem.

Format before review, not during

A workflow detail that keeps diffs readable.

Running the formatter as part of a pre-commit hook means every commit arrives formatted and no commit contains formatting churn. Reviews then show only substantive changes.

Running it manually and occasionally produces the opposite: a large formatting commit every few weeks, mixed into whatever else was being changed at the time.

Where a repository is being formatted for the first time, doing it as a single commit that touches nothing else — and adding that commit to a blame-ignore file — keeps history usable. Most git tooling supports ignoring specific revisions in blame output, which means a repository-wide reformat does not obscure who last changed a line.

Common mistakes to avoid

  • Reformatting and changing resources in the same commit.
  • Fighting the alignment reset at blank lines by manually padding, which the formatter then undoes.
  • Running the formatter locally and having no CI check, so the repository drifts whenever someone forgets.
  • Assuming formatting validates anything — it does not check syntax, references or provider requirements.
  • Formatting generated files that are overwritten on the next run.

How to do it with Terraform HCL Formatter

The Terraform HCL Formatter applies the canonical rules to a pasted snippet.

  1. Paste the HCL — a resource block, a module, or a whole file.
  2. Format to the canonical style with aligned assignment groups.
  3. Copy it back into your configuration.
  4. Add terraform fmt -check -recursive to CI so this stops being a manual step.

The terraform fmt documentation covers the command and its flags. Other developer tools are in the tools directory.

Frequently asked questions

Why do the equals signs align in groups rather than across the block?

Because alignment resets at a blank line or a nested block. Each run of consecutive arguments aligns within itself, which is why one block can have several alignment columns and still be canonically formatted.

Does formatting validate my configuration?

No. It only fixes layout. Use terraform validate for syntax and reference checking, and a plan to see what would actually change.

Should generated files be formatted?

Not usually — they are overwritten on the next generation, so formatting them creates churn with no benefit. Exclude them from the check rather than reformatting them each time.

Final thought

Put terraform fmt -check in CI and reformat once, on its own. After that every diff shows only what actually changes your infrastructure.

Try the free Terraform HCL Formatter

#terraform-fmt#hcl-formatter#infrastructure-as-code#terraform-style#online-tools#free-tools