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-validate

kb/workflow ── Workflow ── beginner

terraform 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`.

view as markdownaka: terraform-validate, hcl-validation

What validate does

terraform validate answers one question: would your HCL compile if Terraform tried to execute it? It runs without contacting AWS, without reading state, and without downloading providers (provided they are already downloaded).

Specifically, validate catches:

  • Broken HCL syntax: an unclosed brace, a missing quote.
  • Unknown arguments: bucket_name instead of bucket on aws_s3_bucket.
  • Wrong types: count = "three" (a number is required).
  • References to resources, variables, or locals that do not exist.
  • Dependency cycles (cycle detected).
  • Wrong function signatures: format() called with no arguments.

What validate does not catch:

  • A bucket with that name is already taken (that is plan/apply territory).
  • You lack permissions in AWS (plan/apply again).
  • Drift in state (that is refresh/plan).
  • A data source that returns an empty result.

Basic usage

bash
cd ~/myproject
terraform init -backend=false   # run once to download the provider
terraform validate

On success:

Success! The configuration is valid.

On error:

Error: Unsupported argument
  on main.tf line 5, in resource "aws_s3_bucket" "demo":
   5:   bucket_name = "my-bucket"
An argument named "bucket_name" is not expected here.
Did you mean "bucket"?

Note that Terraform offers a suggestion via "Did you mean". This works for similar names: bucket_name becomes bucket, tag becomes tags.

Why you need init -backend=false

To validate, Terraform needs the provider binaries; without them it does not know the resource schemas. But terraform init without flags tries to configure the backend. If the backend is remote, it contacts S3 and asks for credentials.

You do not need that on every PR. The standard pattern is:

bash
terraform init -backend=false -input=false
terraform validate
  • -backend=false skips backend setup and does not connect to remote state.
  • -input=false disables interactive prompts (CI has nothing to type).

This is the standard PR-review pattern: check that HCL is valid without touching prod state.

Machine-readable output

For IDE integrations and automation, use -json:

bash
terraform validate -json

Output:

json
{
  "format_version": "1.0",
  "valid": false,
  "error_count": 1,
  "warning_count": 0,
  "diagnostics": [
    {
      "severity": "error",
      "summary": "Unsupported argument",
      "detail": "An argument named \"bucket_name\" is not expected here.",
      "range": {
        "filename": "main.tf",
        "start": {"line": 5, "column": 3},
        "end": {"line": 5, "column": 14}
      }
    }
  ]
}

Any IDE can parse this and highlight errors directly in the editor. All Terraform plugins (VS Code, JetBrains) run this same JSON output under the hood.

How validate differs from plan

validateplan
Contacts the cloudnoyes (refresh)
Reads statenoyes
Downloads provideryes (via init)yes
Speedone secondseconds to minutes
Catches typos and wrong namesyesyes
Catches missing cloud resourcesnoyes
Works in PR without AWS credentialsyesno

Rule of thumb: run validate on every save in the IDE. Run plan on every PR (with credentials).

Pitfalls

  • Validate requires at least one init run. Without .terraform/providers/ in the directory, validate does not know the resource schemas and fails with "provider not configured". In a fresh CI build, run init -backend=false before each validate.

  • Validate checks one root module. If your repository has environments/prod/ and environments/staging/, you need to validate each directory separately. A single validate from the repository root does not cover them all.

  • Validate does not substitute variable values. If HCL references var.foo and the variable is not declared, that is an error. If the variable is declared but has no default, validate passes because the value may arrive at runtime.

  • Validate does not catch logic errors. count = var.enabled ? 1 : 0 passes even if var.enabled is always false: the expression is valid, just useless.

  • Strictness changes between TF versions. In TF 1.5+ validate became stricter about provider-schema incompatibilities. After upgrading TF, run validate against your existing projects.

§ команды

bash
terraform validate

Run locally after init. Checks that HCL is valid.

bash
terraform init -backend=false -input=false && terraform validate

For CI: download providers without connecting to remote state, then validate.

bash
terraform validate -json

Machine-readable output. Used by IDE plugins and CI aggregators.

bash
terraform validate -no-color

Output without ANSI color codes. Useful in CI logs that do not render escape sequences.

§ см. также

  • 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-fmtterraform 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.
  • tf-initterraform init: the first command in any projectterraform init downloads the provider plugins (AWS, GCP, and so on), creates a lockfile that pins their versions, and prepares the working directory. Without it, neither plan nor apply will run.
  • tf-planterraform plan: see what Terraform is about to doplan is a dry run: Terraform reads your HCL, reads the state, and shows the diff between them. It changes nothing in the cloud. This is your main tool for not breaking prod by mistake.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies