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.