skip to content

In Terraform, which variable-definition files does the CLI load automatically, and how do you supply values from a file it does not auto-load, such as prod.tfvars?

level: juniorimportance: should knowfreq 62%

answer

  1. three filename patterns, nothing else
  2. terraform.tfvars plus *.auto.tfvars
  3. lexical order among the auto files
  4. other names need -var-file
  5. no implicit per-workspace tfvars

basics

~10 s

Terraform automatically loads terraform.tfvars, terraform.tfvars.json, and any file ending in .auto.tfvars or .auto.tfvars.json from the directory it runs in. Any other name, such as prod.tfvars, is read only when you pass -var-file=prod.tfvars.

solid answer

~40 s

Terraform auto-loads exactly three filename patterns from the directory it runs in: `terraform.tfvars`, `terraform.tfvars.json`, and any `*.auto.tfvars` or `*.auto.tfvars.json` file, with the auto files processed in lexical order of their filenames. Nothing else is picked up implicitly — `prod.tfvars` or `dev.tfvars` are ordinary files that take effect only when named on the command line with `-var-file`, which you can repeat. That is usually the point: naming per-environment files so they are *not* auto-loaded means you cannot apply production values just by standing in the wrong directory, because the environment has to be spelled out in the command. Auto-loading is not recursive into subdirectories, and it has no relationship to the selected workspace — there is no built-in `<workspace>.tfvars` convention.

code

bash · 11 lines
bash
ls
# main.tf  variables.tf  terraform.tfvars  tags.auto.tfvars  prod.tfvars

# reads terraform.tfvars and tags.auto.tfvars automatically; prod.tfvars is ignored
terraform plan

# reads all three; prod.tfvars overrides the other two where they overlap
terraform plan -var-file=prod.tfvars

# run against a different root module directory
terraform -chdir=envs/prod plan

go deeper

for a junior

Be able to name the auto-loaded patterns — terraform.tfvars, terraform.tfvars.json, *.auto.tfvars — and say that any other filename must be passed with -var-file.

for a middle

Explain that -var-file adds to the auto-loaded files rather than replacing them, that auto files are processed in lexical filename order, and that auto-loading uses the working directory only.

for a senior

Show the judgment behind the naming: per-environment files are deliberately not auto-loaded so a production run has to name its environment, and a committed terraform.tfvars in a shared root module is a hazard.

for a principal

Own the estate-wide convention — directory-per-environment versus one root module with explicit -var-file — and be able to argue why the layout you pick makes the wrong run hard rather than merely discouraged.

## What "auto-loaded" means A `.tfvars` file is just a set of `name = value` assignments for the input variables declared in the root module. Terraform reads some of these files without being told to, purely because of their filename. Everything else is an ordinary file that has no effect until you point at it. Knowing which is which is the difference between "my value is being ignored" and "where did that value come from?". ## The exact list From the current working directory, Terraform loads: - `terraform.tfvars` - `terraform.tfvars.json` - any file matching `*.auto.tfvars` or `*.auto.tfvars.json`, processed in lexical order of their filenames That is the whole list. `prod.tfvars`, `eu-west-1.tfvars`, `vars/common.tfvars` and `values.tf` (a `.tf` file cannot assign variable values at all — it declares them) are not in it. ## Everything else needs -var-file ```bash terraform plan -var-file=envs/prod.tfvars terraform plan -var-file=common.tfvars -var-file=envs/prod.tfvars ``` `-var-file` may be given more than once and accepts both HCL and JSON files. The options are processed in the order they appear, so a later file overrides an earlier one for variables both of them set. Command-line file options also sit above every auto-loaded file in Terraform's precedence order, so a `-var-file` value wins over the same variable set in `terraform.tfvars`. Importantly, `-var-file` **adds** a source; it does not switch auto-loading off. If `terraform.tfvars` is present it is still read, and any variable set only there still applies. That is a frequent source of "but I passed prod.tfvars" confusion in a repo that also carries a committed `terraform.tfvars` full of developer defaults. ## Order among the auto files Lexical order means string order, not numeric order and not the order you would like. `10-network.auto.tfvars` sorts *before* `2-network.auto.tfvars`, because `1` precedes `2` character by character. Since later files override earlier ones, `2-network.auto.tfvars` wins. Zero-padding (`02-`, `10-`) restores the intuitive result. Relying on this ordering at all is fragile; prefer one file per concern with no overlapping variables. ## The working directory, not the repository root Auto-loading looks in the directory Terraform treats as current. With `terraform -chdir=envs/prod plan`, Terraform switches to `envs/prod` first, so the `terraform.tfvars` inside that directory is the one loaded — not the one at the repository root. A `.tfvars` file two directories up is never found automatically; if you want shared values, pass them explicitly with `-var-file=../common.tfvars` or generate them. ## Two common repository layouts **Directory per environment.** `envs/dev/`, `envs/prod/`, each its own root module with its own `terraform.tfvars`. Auto-loading is safe here, because being in the directory *is* choosing the environment, and the backend configuration in that directory pins the state too. **One root module, a file per environment.** `prod.tfvars`, `dev.tfvars` next to a single configuration. Here the files deliberately do **not** end in `.auto.tfvars`, so every run must name one. The cost is that forgetting `-var-file` gives you a run with defaults instead of a loud failure — which is why variables that must never be guessed are declared with no default, so an omitted file becomes an error rather than a surprise. ## Failure modes worth recognising - A committed `terraform.tfvars` in a shared root module quietly seeds everyone's plan, including CI's. - Renaming `dev.tfvars` to `dev.auto.tfvars` makes it apply everywhere, including production runs from that directory. - A value for a variable the root module does not declare produces a warning about a value for an undeclared variable and is ignored, so a typo'd name in a `.tfvars` file silently does nothing. - Terraform does not look inside subdirectories, so `vars/prod.auto.tfvars` is not auto-loaded even though the name matches. ## The mental model Auto-loading is a convenience for "values that always apply in this directory". Anything that varies per run — the environment, a release version, a secret — should be named explicitly on the command line, where a reader of the CI job log can see exactly what went in.

  • Does passing -var-file=prod.tfvars stop Terraform from reading terraform.tfvars?
    No. `-var-file` adds a source rather than replacing the auto-loaded ones, so `terraform.tfvars` is still read. Variables set in both come from the `-var-file`, because command-line file options sit at a higher precedence tier, but any variable set *only* in `terraform.tfvars` still applies. If you want a clean per-environment set, either keep the auto-loaded file to genuinely shared values or use a separate root directory per environment so there is nothing to auto-load.
  • A directory holds 10-network.auto.tfvars and 2-network.auto.tfvars, both setting vpc_cidr. Which one wins?
    `2-network.auto.tfvars`. Auto files are processed in lexical filename order and later files override earlier ones; lexically `10-` sorts before `2-` because the comparison is character by character, not numeric. Zero-padding to `02-` and `10-` gives the ordering people expect. Depending on this at all is brittle — it is better that no two files assign the same variable.
  • Can a .tf file assign a value to a variable the way a .tfvars file does?
    No. A `.tf` file *declares* a variable with a `variable` block and can give it a `default`, but it cannot assign a value to a variable declared elsewhere. Values come from tfvars files, `TF_VAR_` environment variables, `-var`/`-var-file`, or the interactive prompt. A child module's variables are set by arguments in its `module` block, never by a tfvars file.

saying these in an interview costs you the question

  • Thinks every .tfvars file in the directory is loaded automatically
  • Believes selecting a workspace auto-loads a matching workspace tfvars file
  • Assumes -var-file replaces the auto-loaded files instead of adding to them
  • Expects Terraform to search subdirectories or parent directories for tfvars
  • Thinks a .tf file can assign values to variables

context