A Terraform .gitignore ignores the .terraform/ folder that terraform init fills, every state file (*.tfstate, *.tfstate.*), variable files (*.tfvars, *.tfvars.json), local override files, and saved plans (*.tfplan). Those are the key lines of the tool’s Terraform template, which has 14, with crash logs and CLI configuration files making up the rest.
What the blocks ignore
- Downloads:
**/.terraform/*, the providers and modulesterraform initfetches, in every root module. - State:
*.tfstate,*.tfstate.*for backups and the.terraform.tfstate.lock.infolock. State holds every attribute of every resource, secrets included, in plain text; keep it in a remote backend. - Variables:
*.tfvarsand*.tfvars.json, where passwords and keys usually end up. - Local changes:
override.tf,*_override.tfand their JSON forms. - Plans and config:
*.tfplan,crash.log,.terraformrcandterraform.rc, which can hold registry credentials.
In a scratch repository with this file, git check-ignore -v -n --no-index names the line that matched each path, or prints :: when none did:
.gitignore:3:**/.terraform/* envs/prod/.terraform/modules/modules.json
:: .terraform.lock.hcl
:: envs/prod/.terraform.lock.hcl
.gitignore:5:*.tfstate terraform.tfstate
.gitignore:6:*.tfstate.* terraform.tfstate.backup
.gitignore:6:*.tfstate.* .terraform.tfstate.lock.info
.gitignore:10:*.tfvars prod.auto.tfvars
:: terraform.tfvars.example
.gitignore:18:*.tfplan plan.tfplan
:: tfplan
Commit .terraform.lock.hcl
The dependency lock file sits beside .terraform/, not inside it, so it stays tracked, as Terraform’s documentation asks: it pins the exact provider versions and checksums terraform init installs. A broad line such as .terraform* would catch it too, and then every machine picks its own provider versions:
.gitignore:2:.terraform* .terraform.lock.hcl
Saved plans need the extension
terraform plan -out=tfplan writes a file with no extension, which the template misses (:: tfplan above). Name plans *.tfplan, or add the name as a custom line: saved plans aren’t encrypted and can include sensitive values.
Keeping a variables file
*.tfvars also catches *.auto.tfvars files of plain settings you may want to share. A later ! line brings one back, because its folder isn’t excluded:
.gitignore:24:!network.auto.tfvars network.auto.tfvars
.gitignore:10:*.tfvars secrets.auto.tfvars
A file in an excluded folder can’t come back that way. **/.terraform/* excludes .terraform/modules/ as a folder, and Git never looks inside it, so !.terraform/modules/modules.json leaves the file reported against line 3.
Committed state already?
.gitignore only affects untracked files. Untrack the state, keeping it on disk, and commit:
git rm --cached terraform.tfstate terraform.tfstate.backup
git commit -m "Stop tracking Terraform state"
The old versions stay in the history, so rotate any secret they held, and move the state to a remote backend.
Editor and OS files
.idea/, .vscode/ and .DS_Store come from your machine. Keep them in a global ignore file:
git config --global core.excludesFile ~/.gitignore_global