Terraform

Terraform fmt Complete Guide: The Code Formatter for the Associate Exam and Production

2026-04-19
NicheeLab Editorial Team

terraform fmt automatically rewrites Terraform language files into the official canonical style. It directly improves code readability and keeps diffs stable.

The HashiCorp Terraform Associate exam frequently asks about the role of fmt, how it differs from validate, and how to use it in CI. This guide sticks to the stable, official behavior and turns it into knowledge you can apply directly at work.

terraform fmt Basics and Exam Points

terraform fmt rewrites Terraform language files such as .tf and .tfvars in place according to the official style. It does not change syntax or meaning — it only normalizes layout: whitespace, indentation, and line breaks.

On the Associate exam, you'll be asked questions like "which command unifies code style?" or "how do you detect formatting drift in CI and fail the build?" Be clear that fmt has a different role than syntax validation (validate) or planning execution (plan).

  • By default it formats files in the current directory (no recursion)
  • You can pass a directory or an individual file as an argument
  • The formatting style follows Terraform's official canonical form
  • The JSON variants (.tf.json / .tfvars.json) are not formatted
  • Detecting syntax errors is out of scope (that is validate's job)

Basic usage

terraform fmt
terraform fmt main.tf
terraform fmt ./modules/network

Key Options and Production Combinations

In production the combinations you'll reach for most are -recursive (recurse), -check (detect drift without rewriting), -diff (show diffs), -write=false (output only, no overwrite), and -list=false (suppress file name listing). Pick the right ones for your goal.

The standard CI approach is to detect drift and fail without rewriting files, optionally showing a diff. Locally, in-place rewriting is fine.

  • -recursive: process subdirectories too. Useful in large repositories
  • -check: decide whether formatting is needed without rewriting. Exits non-zero if any file is unformatted
  • -diff: show required changes as a unified diff
  • -write=false: do not overwrite files; print the formatted result to stdout
  • -list=false: suppress the list of files with formatting differences (cleaner logs)
  • -no-color: use alongside the above to improve CI log readability

Commonly used command examples

# Recursively rewrite the whole repository in place (local work)
terraform fmt -recursive

# For CI: do not rewrite, show diffs, fail if anything is unformatted
terraform fmt -check -diff -recursive

# Keep logs clean (suppress file name listing)
terraform fmt -check -diff -list=false -recursive

# Preview only (do not overwrite). Best for a single file
terraform fmt -write=false main.tf > main.tf.preview

Design and Workflow for CI Integration

In CI, run terraform fmt -check -diff -recursive per pull request and fail the pipeline if anything is unformatted. With -diff, reviewers can see exactly what needs to change directly in the PR logs.

For consistent results across the team, use the same Terraform version line in CI and locally. The formatting rules are built into the official implementation, so no additional tools need to be installed.

  • Failure condition: any single unformatted file
  • Show diffs with -diff; do not rewrite (-check takes precedence)
  • Fail the PR to push developers to run fmt locally
  • In large monorepos, narrowing the target directories also works well

Basic CI flow (example)

Dev(open PR)CI Trigger(PR/Open/Push)terraform fmt -check-diff -recursivevalidate(optional)plan/applyon protected branchDev → CI Trigger → terraform fmt -check -diff -recursive → validate → plan/apply (on protected branch)

GitHub Actions example

name: terraform-fmt-check
on:
  pull_request:
jobs:
  fmt:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.x
      - name: Check formatting
        run: terraform fmt -check -diff -recursive

What fmt Targets, What It Skips, and Path-Design Tips

fmt primarily targets Terraform language files (.tf, .tfvars, .auto.tfvars, etc.). The JSON variants (.tf.json / .tfvars.json) are out of scope. The contents of language literals such as template strings and heredocs are not modified in principle.

When recursing, fmt walks below the given directory. The .terraform directory that holds dependency modules is normally not version-controlled. In CI, it is safer to specify paths explicitly or use shell find to exclude it so it doesn't accidentally get processed.

  • Targets: .tf, .tfvars, .auto.tfvars and other Terraform language files
  • Out of scope: .tf.json, .tfvars.json (JSON variants)
  • String literal contents (including heredocs) are preserved as a rule
  • It is safer to narrow targets with explicit paths (e.g., ./modules, ./envs)

Format while excluding the .terraform directory (bash example)

# Exclude .terraform and fmt each .tf found
find . -type d -name .terraform -prune -o -name '*.tf' -print0 | xargs -0 -n1 terraform fmt

Common Pitfalls and Troubleshooting

terraform fmt -write=false means "do not overwrite — print the formatted output to stdout". Applied across multiple files, the outputs concatenate, so it is safer to limit preview use to a single file. To see diffs, use -diff.

When diffs remain after formatting, the cause is often something outside fmt's scope — whitespace or newlines inside string literals, comment positions, etc. Also, subtle formatting differences can appear between Terraform major/minor versions, so aligning CLI versions across the team keeps things stable.

  • For previews use -diff, or a single file with -write=false
  • Note that -write=false with multiple files mixes the outputs together
  • fmt only changes style. Detecting syntax errors is validate's job
  • Mixed CLI versions can produce subtle differences

Heredoc contents are preserved (example)

resource "local_file" "example" {
  content = <<-EOT
  indented line
  another   spaced   line
  EOT
  filename = "example.txt"
}
# fmt normalizes blocks and indentation, but whitespace inside the heredoc is preserved.

For the Exam: How fmt Differs from Other Commands (Key Points)

A frequent Associate-level question is how fmt and validate divide responsibilities. fmt unifies style, validate performs syntax and some static checks, and plan creates an execution plan — three distinct purposes. Behavior does not change based on formatting, but for review-friendliness and stable diffs, fmt is essential.

Linters (e.g., tflint) check for best practices and policy compliance, but they are not part of the official CLI. On the exam, prioritize the roles of official commands when answering.

  • fmt: normalizes appearance (style); does not change meaning
  • validate: static checks on syntax and references; does not change meaning
  • plan: produces a plan of changes; talks to state and providers
  • tflint (reference): best-practice checks; unofficial
Command / ToolPrimary PurposeOverwrites FilesTypical Failure Condition
terraform fmtNormalize style (format)Yes by default (-write=false to disable)Unformatted files (exits non-zero with -check)
terraform validateValidate syntax, types, referencesNoSyntax or reference errors detected
tflint (reference)Best-practice checks via lintNoRule violations detected (depends on config)

Minimal fmt → validate pipeline example

terraform fmt -recursive .
terraform validate

Check with a Practice Question

Associate

問題 1

In your team's CI, you want to fail the build when Terraform code isn't formatted in the official style, and show the required changes as a diff in the log. Which command is most appropriate?

  1. terraform fmt -check -diff -recursive
  2. terraform fmt -write=false -recursive
  3. terraform validate -no-color
  4. terraform plan -out=tfplan

正解: A

To detect unformatted files without rewriting them and show the required changes in CI, combining -check and -diff is the right choice. Use -recursive to cover subdirectories. -write=false only prints to stdout — it does not detect or fail on formatting drift. validate and plan have different purposes.

Frequently Asked Questions

Does terraform fmt format .tf.json or .tfvars.json files?

No. terraform fmt targets Terraform language files (.tf, .tfvars, etc.) and does not format the JSON variants (.tf.json, .tfvars.json).

Is there a fixed exit code when unformatted files are detected?

terraform fmt formats files by default. When you pass -check, it exits with a non-zero code if any unformatted file is found. It is safer not to depend on a specific numeric value.

Where should terraform fmt run in a project?

Run it locally on save or before commit, and in CI run terraform fmt -check -diff -recursive on pull requests. In large repositories, explicitly scope the target directories and exclude artifacts like .terraform for safety.

Check what you learned with practice questions

Practice with certification-focused question sets

無料で問題を解いてみる
Author

NicheeLab Editorial Team

NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.


Related articles
Terraform

HCL Syntax: Terraform's Configuration Language (2026)

HCL2 fundamentals for Terraform — blocks, attributes, expres...

Terraform

Terraform Authoring & Operations Pro: Complete Guide (2026)

Tactics for the Terraform Pro exam — module authoring, works...

Terraform

Terraform Providers: Plugin Management Fundamentals (2026)

Provider mechanics — required_providers, versions, mirrors, ...

Terraform

Terraform Resource Blocks: Declarative Infra Units (2026)

Resource block fundamentals — addresses, references, common ...

Terraform

Terraform Data Sources: Read-Only External Data (2026)

Data source basics — declaration, refresh behavior, dependen...

Browse all Terraform articles (102)
© 2026 NicheeLab All rights reserved.