Skip to main content
TFLint: Lint and Validate Terraform Code Before Apply

TFLint: Lint and Validate Terraform Code Before Apply

Key Takeaway

Install and configure TFLint to catch Terraform errors before terraform apply. Covers AWS/Azure/GCP plugins, .tflint.hcl config, CI/CD integration

Table of Contents

What Is TFLint?

TFLint is a linter for Terraform that catches errors terraform validate misses. It checks for:

  • Invalid instance types (t2.gigantic doesn’t exist)
  • Deprecated resource attributes
  • Naming convention violations
  • Provider-specific best practices (AWS, Azure, GCP)
  • Missing required tags

terraform validate only checks syntax. TFLint checks whether your configuration makes sense.

Install TFLint

macOS (Homebrew)

brew install tflint

Linux

curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash

Windows (Chocolatey)

choco install tflint

Docker

docker run --rm -v $(pwd):/data -t ghcr.io/terraform-linters/tflint

Verify installation:

$ tflint --version
TFLint version 0.53.0

Quick Start

cd my-terraform-project/
tflint --init    # Download plugins
tflint           # Run linter

That’s it. TFLint scans all .tf files in the current directory.

Configure TFLint: .tflint.hcl

Create .tflint.hcl in your project root:

# .tflint.hcl

# Enable the AWS plugin
plugin "aws" {
  enabled = true
  version = "0.32.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}

# Enforce naming conventions
rule "terraform_naming_convention" {
  enabled = true
}

# Require descriptions on variables
rule "terraform_documented_variables" {
  enabled = true
}

# Require descriptions on outputs
rule "terraform_documented_outputs" {
  enabled = true
}

# Disallow deprecated syntax
rule "terraform_deprecated_interpolation" {
  enabled = true
}

# Enforce standard module structure
rule "terraform_standard_module_structure" {
  enabled = true
}

Then initialize:

$ tflint --init
Installing `aws` plugin...
Installed `aws` (source: github.com/terraform-linters/tflint-ruleset-aws, version: 0.32.0)

What TFLint Catches (That terraform validate Doesn’t)

Invalid Instance Types

resource "aws_instance" "web" {
  ami           = "ami-12345678"
  instance_type = "t2.superduper"  # Doesn't exist!
}
$ tflint
1 issue(s) found:

Error: "t2.superduper" is an invalid value as instance_type (aws_instance_invalid_type)

  on main.tf line 3:
   3:   instance_type = "t2.superduper"

terraform validate would pass this. terraform apply would fail after waiting for the API call.

Invalid AMI

resource "aws_instance" "web" {
  ami = "not-an-ami"
}

TFLint catches the invalid AMI format before you waste time on a failed plan.

Deprecated Syntax

# Old interpolation-only syntax
resource "aws_instance" "web" {
  instance_type = "${var.instance_type}"  # Deprecated since Terraform 0.12
}
Warning: Interpolation-only expressions are deprecated (terraform_deprecated_interpolation)

Missing Tags

With the AWS plugin, you can enforce required tags:

# In .tflint.hcl
rule "aws_resource_missing_tags" {
  enabled = true
  tags = ["Environment", "Team", "ManagedBy"]
}

Now every AWS resource must have these tags or TFLint reports an error.

Provider Plugins

AWS Plugin

plugin "aws" {
  enabled = true
  version = "0.32.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}

Checks: invalid instance types, invalid AMIs, invalid IAM policy actions, security group rules, and more.

Azure Plugin

plugin "azurerm" {
  enabled = true
  version = "0.27.0"
  source  = "github.com/terraform-linters/tflint-ruleset-azurerm"
}

Google Cloud Plugin

plugin "google" {
  enabled = true
  version = "0.30.0"
  source  = "github.com/terraform-linters/tflint-ruleset-google"
}

Built-In Terraform Rules

These rules work without any provider plugin:

RuleWhat It Checks
terraform_naming_conventionResource/variable/output naming patterns
terraform_documented_variablesVariables have descriptions
terraform_documented_outputsOutputs have descriptions
terraform_deprecated_interpolation"${var.x}"var.x
terraform_unused_declarationsUnused variables, data sources, locals
terraform_standard_module_structuremain.tf, variables.tf, outputs.tf exist
terraform_workspace_remoteWarns about terraform.workspace with remote backends
terraform_required_versionrequired_version is declared
terraform_required_providersrequired_providers block exists

Enable them all for strict projects:

rule "terraform_naming_convention" { enabled = true }
rule "terraform_documented_variables" { enabled = true }
rule "terraform_documented_outputs" { enabled = true }
rule "terraform_deprecated_interpolation" { enabled = true }
rule "terraform_unused_declarations" { enabled = true }
rule "terraform_standard_module_structure" { enabled = true }
rule "terraform_required_version" { enabled = true }
rule "terraform_required_providers" { enabled = true }

CI/CD Integration

GitHub Actions

name: Terraform Lint
on: [pull_request]

jobs:
  tflint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: terraform-linters/setup-tflint@v4
        with:
          tflint_version: v0.53.0
      - run: tflint --init
      - run: tflint --format compact

GitLab CI

tflint:
  image: ghcr.io/terraform-linters/tflint:latest
  script:
    - tflint --init
    - tflint --format compact
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Pre-Commit Hook

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/terraform-linters/tflint
    rev: v0.53.0
    hooks:
      - id: tflint

Output Formats

tflint                     # Default (human-readable)
tflint --format compact    # One line per issue
tflint --format json       # Machine-readable JSON
tflint --format junit      # JUnit XML for CI
tflint --format sarif      # SARIF for GitHub Code Scanning

TFLint vs Other Tools

ToolWhat It DoesWhen to Use
terraform validateSyntax check onlyAlways (fast, built-in)
TFLintSyntax + provider-specific + best practicesAlways (catches real errors)
terraform planFull API check against real infrastructureBefore apply
tfsec / trivySecurity scanningSecurity audits
checkovPolicy complianceCompliance requirements
terraform-docsGenerate documentationModule documentation

Recommended pipeline order: terraform fmttflintterraform validateterraform plan

Common Configuration Examples

Enforce snake_case naming:

rule "terraform_naming_convention" {
  enabled = true
  format  = "snake_case"
}

Ignore specific rules for a module:

tflint --ignore-rule=terraform_documented_variables

Lint a specific directory:

tflint --chdir=modules/vpc/

Recursive lint (all modules):

tflint --recursive

Hands-On Courses

Learn by doing with interactive courses on CopyPasteLearn:

Conclusion

TFLint catches real errors that terraform validate misses — invalid instance types, missing tags, deprecated syntax, naming violations. Install it, add a .tflint.hcl with the AWS/Azure/GCP plugin, and integrate it into your CI pipeline. Run tflint before terraform plan to catch mistakes before they reach infrastructure.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.