What Is terraform validate?
terraform validate checks that your Terraform files are syntactically correct HCL and internally consistent — meaning every resource reference points to something that actually exists in the configuration — without needing any cloud credentials at all. It is the fastest possible check you can run, because it never talks to AWS, GCP, or any API.
Think of it as a spell-checker for your Terraform code. It catches typos in block syntax, missing required arguments, and references to undeclared variables. What it cannot tell you is whether AWS will actually accept the values you have given it — that is what plan is for.
What Is Tflint?
Tflint goes a step further than validate — it is a dedicated linter that understands provider-specific rules. validate will happily pass a configuration that uses a deprecated EC2 instance type or forgets a recommended tag, because that is not a syntax error. Tflint catches exactly these kinds of "technically valid, practically wrong" issues.
At PhonePe, the CI pipeline runs both tools in sequence on every pull request, before anything resembling a real terraform plan against AWS credentials happens. This catches roughly 80% of the obviously broken PRs — a missing closing brace, a renamed variable nobody updated, a deprecated AWS instance family — in under five seconds, instead of waiting two minutes for a full provider-authenticated plan to fail with the same error.
Validate vs Plan — Knowing the Difference
terraform validate terraform plan- Runs OFFLINE, no credentials needed - Needs real cloud credentials- Checks syntax and internal refs - Checks against REAL infrastructure- Takes under 1 second - Takes seconds to minutes- Catches: typos, missing arguments, - Catches: invalid AMI IDs, IAM undeclared variable references permission errors, quota limitsRunning terraform validate
terraform init -backend=false # skip backend setup — validate doesn't need stateterraform validate # Success output:# Success! The configuration is valid. # Failure output (an actual undeclared variable reference):# Error: Reference to undeclared input variable# on main.tf line 12, in resource "aws_instance" "app":# 12: instance_type = var.intsance_type# An input variable with the name "intsance_type" has not been declared.# ^^^^^^^^^^^^^^^^ typo — should be instance_typeWhat validate Catches vs What It Misses
COMMON MISTAKE / WARNINGCommon mistake: assuming a clean `terraform validate` means your code is correct. It only proves the HCL is well-formed. It will not catch an AMI ID that does not exist in your target region, an IAM policy that grants no actual permissions, or a CIDR block that overlaps with an existing subnet — all of those only surface during `plan` or `apply`, because they require real cloud-side knowledge.
Installing and Configuring Tflint
# Install tflint (macOS/Linux via the official install script)curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash # Initialize tflint in your project — downloads any configured pluginstflint --init# .tflint.hcl — configuration file at the repo rootplugin "aws" { enabled = true version = "0.31.0" source = "github.com/terraform-linters/tflint-ruleset-aws"} rule "terraform_required_version" { enabled = true # forces every module to declare required_version} rule "terraform_required_providers" { enabled = true # forces every module to pin its provider versions}Running Tflint with the AWS Plugin
tflint # Example output catching a deprecated instance type:# main.tf# 12:12 warning "t2.micro" is previous generation. Consider using "t3.micro" instead.# (aws_instance_previous_type)## 18:3 error "ap-south1" is an invalid value for region. (aws_instance_invalid_ami)# typo caught — should be "ap-south-1"Integrating Both into a CI Pipeline
# .github/workflows/terraform-lint.yml- name: Terraform Format Check run: terraform fmt -check -recursive - name: Terraform Validate run: | terraform init -backend=false terraform validate- name: Tflint run: | tflint --init tflint --recursiveINFORMATIONTip from a senior engineer: order matters in CI. Run `fmt -check`, then `validate`, then `tflint`, then only after all three pass, run the real authenticated `plan`. Each stage is progressively more expensive — fail on the cheapest check first and you save real CI minutes (and money) on every broken PR.
Quick Reference
| Tool | Needs Credentials? | Catches |
|---|---|---|
terraform fmt -check |
No | Formatting/style inconsistencies only |
terraform validate |
No | Syntax errors, undeclared references |
tflint |
No | Deprecated syntax, provider-specific rule violations |
terraform plan |
Yes | Real cloud-side errors — invalid AMIs, IAM issues, quota limits |
| Error | Root Cause | Fix |
|---|---|---|
Error: Unsupported argument |
Argument name doesn't exist on that resource type | Check the provider documentation for the exact argument name |
Error: Missing required argument |
A required field was left out of the resource block | Add the missing argument — the error names it explicitly |
| Tflint reports rule violations validate did not catch | This is expected — they check different things | Treat tflint failures seriously even when validate passed cleanly |
Failed to load plugins in tflint |
Plugin version in .tflint.hcl doesn't match what tflint --init downloaded |
Re-run tflint --init after updating the plugin version |