Terraform .gitignore Generator and Checker

Check a Terraform .gitignore. One very common pattern in these files does real damage, and it looks more careful than the correct version.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Check. Nothing leaves this tab.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

The wildcard that eats the lock file

Matches .terraform.lock.hcl as well as the directory, so provider versions stop being pinned

.terraform*
*.tfstate
*.tfstate.*
*.tfvars
!terraform.tfvars.example

State ignored, backups not

terraform.tfstate.backup holds the same secrets and *.tfstate does not match it

.terraform/
*.tfstate
*.tfplan
*.tfvars

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Writing .terraform* instead of .terraform/

    The wildcard matches .terraform.lock.hcl as well as the directory, so the lock file is never committed and provider versions stop being pinned. Nothing reports it.

    Instead:Use .terraform/ with the trailing slash, and commit .terraform.lock.hcl.

  2. Ignoring *.tfstate and not *.tfstate.*

    Terraform writes terraform.tfstate.backup next to the state, and the first pattern does not match it. The backup holds the same secrets.

    Instead:Add both patterns, or use *.tfstate* to cover them together.

  3. Ignoring every tfvars file with nothing left as a template

    Safe, and it leaves each new contributor to reconstruct the variable list from variables.tf.

    Instead:Keep the blanket ignore and add !terraform.tfvars.example with placeholder values in it.

.terraform* and .terraform/ are one character apart and opposite

Somebody means the working directory, writes the wildcard, and takes the lock file with it. Nothing warns you, because a missing lock file just means the next init picks whatever is newest.

The lock file must be committed

.terraform.lock.hcl records which provider versions were selected and their checksums. It is the only thing that stops two people getting different providers from identical configuration, and the only record of what was actually used. Ignoring it is the commonest mistake in a Terraform repository, and .terraform* is nearly always how it happens.

State and its backup are both secrets

A state file holds the resolved value of every attribute, so committing one commits every generated password and private key, permanently, in the history. *.tfstate does not match terraform.tfstate.backup, which Terraform writes alongside it and which contains the same values. Both patterns are needed.

A saved plan is as sensitive as state

A .tfplan carries the values it is about to write, unredacted, and so does the JSON produced from it. Plan files get committed most often when somebody converts one to JSON in the working directory to read it.

Blanket-ignore tfvars and keep an example back

*.tfvars stops a credential being committed by accident, and it also hides the file a new contributor would have copied. The pattern that works is the blanket ignore plus !terraform.tfvars.example, so there is a committed template with no real values in it.

override.tf changes the configuration silently

Terraform merges override.tf and *_override.tf over everything else, which makes them a local experimentation mechanism. Committed, they change behaviour for everybody and are easy to miss when reading a diff. HashiCorp's own recommended ignore file lists them.

Crash logs contain fragments of what was running

When Terraform panics it writes a crash log with a stack trace and pieces of the state or plan it was working on, which can include attribute values.

More terraform tools

Terraform Validator & Formatter Does it parse, and is it formatted? Terraform dynamic Block Generator It is ingress.value, not each.value Terraform check and precondition Generator A failed check does not stop the apply Terraform variables.tf Generator From the var. references you already wrote Terraform Unused Declaration Linter Dead variables, locals and data sources Terraform Atlantis YAML Generator when_modified misses your modules Terraform Function Tester and HCL Console terraform console, in a tab Terraform for Expression Tester Where do the keys collide? Terraform Interpolation Tester null becomes an empty string Terraform templatefile Tester Render it before you apply it Terraform Resource Count Calculator How many objects, not how many blocks Terraform count to for_each Converter With the moved blocks it needs Terraform moved Block Generator Rename without destroying Terraform state mv Command Builder No plan, no undo Terraform target Flag Builder And why to stop using it Terraform outputs.tf Generator Outputs are not sensitive by default Terraform Remote State Data Source Generator It grants read of the whole state Terraform Provider Block Generator docker is not hashicorp/docker Terraform to OpenTofu Migration Checker The state is the part to watch Terraform tfvars to JSON Converter The JSON file wins Terraform Version Constraint Parser What ~> actually allows Terraform Resource Address Parser Quote it before the shell eats it Terraform cidrsubnet Calculator newbits is added, not the target Terraform Import Block Generator The id is not the name Terraform Lock File Viewer Why CI fails and your laptop does not Terraform Variables Checker A missing value hangs CI Terraform tfvars to Env Vars Converter Lists and maps have to be JSON Terraform Deprecated Syntax Checker What a current Terraform rejects Terraform State File Viewer Read it without uploading it Terraform Plan JSON Viewer It is not redacted Terraform HCL to JSON Converter And what the conversion loses Terraform Module Source Validator version only works for the registry Terraform Backend Config Decoder Is state actually locked? Terraform Naming Convention Validator A hyphen makes a resource unreferenceable

Elsewhere on the site