TFLint¶
TFLint catches what terraform validate shrugs off — invalid instance types, malformed ARNs, deprecated syntax — before you waste a plan cycle discovering them. It is a pluggable linter framework: core ships generic rules, and provider-specific rulesets load as separate plugins declared in .tflint.hcl. Cheap insurance against a typo costing an hour of CI.
2026 Update
v0.64.x is current (v0.64.0 shipped July 17, 2026), MPL-2.0 licensed under the terraform-linters org. Release verification moved to GitHub Artifact Attestations (gh attestation verify) — cosign signatures are deprecated. The official GitHub Action (terraform-linters/setup-tflint) tracks the v6.x line, and editor support comes via the built-in language server.
Quick Hits¶
# Install via mise
mise use -g tflint@0.64 # (1)!
# Download plugins declared in .tflint.hcl
tflint --init # (2)!
# Lint the current directory
tflint # (3)!
# Provider-aware checks — run AFTER terraform init so schemas load
terraform init && tflint # (4)!
# SARIF output for GitHub Code Scanning
tflint --format sarif # (5)!
- mise resolves the release binary through its aqua backend — no system package manager involved.
- Nothing downloads until you ask — plugins are declared in config, fetched by
--init. - Generic core rules run without plugins or cloud access.
- Provider plugins resolve real schemas from the initialized environment — this catches invalid instance types and malformed ARNs.
- Formats available: default, compact, json, checkstyle, junit, sarif.
Real talk:
- Provider-aware checks require
terraform initfirst; opt-in deep checks additionally needdeep_check = truein the plugin block plus credentials. - Core rules alone catch generic HCL issues; the provider plugins catch everything interesting.
- Verify downloaded binaries with
gh attestation verify— cosign verification is dead as of 2026.
A working .tflint.hcl — plugin plus rule tuning:
# .tflint.hcl
plugin "aws" {
enabled = true
version = "0.x" # pin an exact version — floating breaks builds
source = "github.com/terraform-linters/tflint-ruleset-aws"
# deep_check = true # opt-in API validation; requires AWS credentials
}
rule "terraform_deprecated_syntax" {
enabled = true
}
rule "aws_instance_previous_type" {
enabled = false # legacy t2 fleet; re-enable after migration
}
Monorepo? Lint every module in one pass:
CI with SARIF upload to GitHub Code Scanning:
# .github/workflows/tflint.yml (excerpt)
steps:
- uses: terraform-linters/setup-tflint@v6 # official action (v6.x line)
- run: tflint --init
- name: Lint all modules
run: tflint --recursive --format sarif > tflint.sarif
# Upload tflint.sarif via github/codeql-action/upload-sarif
# so findings land in the Security tab
Why this works:
- Plugin declarations make the toolchain explicit and auditable — no surprise downloads mid-build.
- Rule blocks kill noise at the source instead of ignoring findings one by one.
--recursivereplaces per-directory shell loops; module linting stays consistent across the tree.- Uploading SARIF via
github/codeql-action/upload-sarifputs lint findings next to CodeQL results where triage already happens.
Tips:
- Pin plugin versions in
.tflint.hcl— unpinned plugins upgrade out from under CI without warning. - Run
--recursivein monorepos instead of looping over directories with shell scripts. - Wire TFLint into pre-commit AND CI: pre-commit catches it locally, CI catches everyone who bypassed the hooks.
Gotchas:
- TFLint is a linter, not a security scanner — pair it with checkov or Trivy for policy and compliance findings.
- Deep checks call the cloud API with your provider credentials — scope them read-only and plan auth for CI.
- Plugin SDK mismatches break old custom plugins — anything built on the SDK v0.25 era needs rebuilding against the current SDK.
Reference¶
Documentation:
Related:
- checkov
- Terraform
Last Updated: 2026-08-22 | Vibe Check: Cheap Insurance - One config file catches the Terraform mistakes that otherwise surface as failed applies at the worst time.
Tags: iac, linter, terraform