linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
home/terraform/kb/Workflow/tf-fmt

kb/workflow ── Workflow ── beginner

terraform fmt: canonical HCL formatting

`terraform fmt` rewrites HCL to a canonical style: consistent indentation, aligned `=` signs, no extra blank lines. It runs on the current directory by default, or recursively with `-recursive`. In CI, use `-check -diff` to fail the build on unformatted files.

view as markdownaka: terraform-fmt, hcl-formatting

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:

bash
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:

bash
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:

hcl
resource "aws_s3_bucket"     "demo" {
     bucket="my-bucket"
  tags={
    Owner="student"
    Env  ="dev"
  }
}

After terraform fmt:

hcl
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.

bash
# 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:

yaml
# .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. Resource instead of resource is an error, not a style issue. validate catches 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

  • fmt writes to disk by default. If a colleague has a file open in an editor with unsaved changes and you run fmt, 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 -recursive also 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 fmt in 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.

§ команды

bash
terraform fmt

Format all .tf and .tfvars files in the current directory and write the changes to disk.

bash
terraform fmt -recursive

Same, but recurse into all subdirectories. Required when the project has a modules/ directory.

bash
terraform fmt -check -recursive

CI mode: do not write; exit with code 3 if anything is unformatted.

bash
terraform fmt -check -diff -recursive

CI mode with diff output: shows exactly what is wrong so the developer can fix it locally.

bash
terraform fmt -

Read HCL from stdin and write the formatted result to stdout. Useful in scripts.

§ см. также

  • hcl-syntaxHCL: the language you write Terraform inHCL (HashiCorp Configuration Language) is the language you use to describe the desired state of your infrastructure. It looks like JSON, but it is easier to read: you can write comments, variables, and loops.
  • tf-validateterraform validate: checking HCL without the cloud`terraform validate` checks HCL for syntax errors and basic logic issues: unknown arguments, wrong types, and references to resources that do not exist. It does not contact the cloud and does not touch state, so it runs fast. In CI, run it after `init -backend=false` and before `plan`.
  • tf-cli-configTerraform CLI configuration: terraformrc, env vars, TF_LOGYou configure the Terraform CLI through the ~/.terraformrc file and the TF_* environment variables. This is where the plugin cache lives, along with TF_LOG for debugging, TF_VAR_* for variables, and TF_CLI_ARGS for global flags.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies