# How to parameterize a template with a tfvars file

Source: https://docs.quake.ai/docs/automation/how-to/parameterize-template-tfvars
Markdown: https://docs.quake.ai/docs/automation/how-to/parameterize-template-tfvars.md

---

# How to parameterize a template with a tfvars file

Reuse the same OpenTofu template in development, staging, and production without forking the HCL. Store environment-specific values in `.tfvars` files and pass them with `-var-file` at plan and apply time.

This guide applies to any template under [Automation templates](/resources/iac-templates) that declares variables in `variables.tf`.

## Prerequisites

- OpenTofu or Terraform installed and Quake AI credentials configured (see [Get started with IaC](/docs/automation/how-to/getting-started-iac))
- A template copied from `iac/templates/` or checked out as your working directory, with `tofu init` already run
- Familiarity with OpenTofu variables (see [How to manage multiple environments with OpenTofu](/docs/automation/how-to/multi-environment) for the broader per-environment pattern)

## Identify variables to externalize

Open `variables.tf` in your template directory. Every template exposes a set of input variables with optional defaults. Values you change per environment or per deployment belong in a tfvars file, not in edited defaults inside `variables.tf`.

The [simple-vm](/resources/iac-templates/simple-vm) template declares six variables:

| Variable | Default | Typical override |
| --- | --- | --- |
| `flavor_name` | `s1a.small` | Larger flavor in production |
| `image_name` | `Ubuntu-24.04` | Pin a specific OS build |
| `key_name` | (required) | Same key across environments |
| `instance_name` | `simple-vm` | Prefix with environment name |
| `external_network` | `PublicStatic` | Rarely changes |
| `private_cidr` | `10.10.10.0/24` | Unique CIDR per environment |

The [edge-reverse-proxy](/resources/iac-templates/edge-reverse-proxy) template adds proxy and upstream settings:

| Variable | Default | Typical override |
| --- | --- | --- |
| `flavor_name` | `s1a.small` | Size up web nodes |
| `domain` | (empty) | Environment-specific hostname |
| `upstream_host` | `10.42.0.10` | Private address of the application |
| `private_cidr` | `10.42.0.0/24` | Unique CIDR per environment |

Required variables such as `key_name` have no default. You must set them in a tfvars file or pass them with `-var` on the command line.

## Create a base tfvars file

Add `terraform.tfvars` in the template directory for values that apply to every environment:

```hcl
# terraform.tfvars: shared across all environments
key_name         = "deploy-key"
external_network = "PublicStatic"
image_name       = "Ubuntu-24.04"
```

OpenTofu loads `terraform.tfvars` automatically on every `plan` and `apply`. You do not pass a flag for this file.


Add `*.tfvars` and `*.auto.tfvars` to `.gitignore` when tfvars files contain environment-specific names or CIDRs you do not want in version control. Commit a `terraform.tfvars.example` with placeholder values instead.


## Add per-environment override files

Create one tfvars file per environment under an `envs/` subdirectory:

```text
iac/templates/simple-vm/
  main.tf
  variables.tf
  terraform.tfvars
  envs/
    dev.tfvars
    prod.tfvars
```

`envs/dev.tfvars`:

```hcl
instance_name = "dev-simple-vm"
flavor_name   = "s1a.small"
private_cidr  = "10.10.10.0/24"
```

`envs/prod.tfvars`:

```hcl
instance_name = "prod-simple-vm"
flavor_name   = "m2a.large"
private_cidr  = "10.10.100.0/24"
```

For [edge-reverse-proxy](/resources/iac-templates/edge-reverse-proxy), set the hostname and upstream per environment:

`envs/dev.tfvars`:

```hcl
domain        = "dev.example.com"
upstream_host = "10.40.0.20"
flavor_name   = "s1a.small"
private_cidr  = "10.40.0.0/24"
```

`envs/prod.tfvars`:

```hcl
domain        = "www.example.com"
upstream_host = "10.41.0.20"
flavor_name   = "m2a.large"
private_cidr  = "10.41.0.0/24"
```

Later files passed with `-var-file` override earlier values. OpenTofu merges `terraform.tfvars` first, then each `-var-file` in the order you specify.

## Plan and apply with `-var-file`

From the template directory, pass the environment file explicitly:

```bash
tofu plan -var-file=envs/dev.tfvars
tofu apply -var-file=envs/dev.tfvars
```

For production:

```bash
tofu plan -var-file=envs/prod.tfvars
tofu apply -var-file=envs/prod.tfvars
```

Pass multiple var-files when a shared baseline and an environment override live in separate files:

```bash
tofu apply -var-file=envs/common.tfvars -var-file=envs/prod.tfvars
```

Values in `prod.tfvars` win over `common.tfvars` for any variable defined in both.

## Pair tfvars with separate state

Variable files control **what** OpenTofu provisions. They do not isolate **state**. Dev and production must use different state files so a `tofu destroy` in dev never touches production resources.

If you use a remote backend, pass a different state key per environment during init:

```bash
tofu init -backend-config="key=dev/simple-vm.tfstate"
tofu apply -var-file=envs/dev.tfvars
```

For production, re-init with a different key:

```bash
tofu init -reconfigure -backend-config="key=prod/simple-vm.tfstate"
tofu apply -var-file=envs/prod.tfvars
```

The full remote-backend setup lives in [How to manage OpenTofu state with Quake AI S3](/docs/automation/how-to/state-management). The directory-per-environment alternative is in [How to manage multiple environments with OpenTofu](/docs/automation/how-to/multi-environment).

## Verify the active variable values

After apply, read the values OpenTofu wrote to state:

```bash
tofu show
```

Search the output for resource attributes such as `flavor_name` and `instance_name`. State reflects the `-var-file` values from apply, not the defaults in `variables.tf`.

To inspect variable resolution before a plan, pass the same `-var-file` flag to the console:

```bash
tofu console -var-file=envs/dev.tfvars
```

At the prompt, read a variable:

```text
> var.flavor_name
"s1a.small"
```

Type `exit` to leave the console.

For compute templates, cross-check the flavor against the live catalog:

```bash
openstack server list -f table -c Name -c Flavor
```

If a plan fails with `value must be known` or `No value for required variable`, the variable is missing from both `terraform.tfvars` and the `-var-file` you passed. Add it to the tfvars file or pass `-var 'key_name=deploy-key'` on the command line.

## See also

- [Automation templates](/resources/iac-templates): reference pages for all deployment patterns
- [How to customize a template's image and flavor](/docs/automation/how-to/customize-template-image-flavor): pick catalog values to put in tfvars
- [How to manage multiple environments with OpenTofu](/docs/automation/how-to/multi-environment): variable files vs directory-per-environment
- [How to manage OpenTofu state with Quake AI S3](/docs/automation/how-to/state-management): remote state keys per environment
- [How to debug Terraform errors](/docs/automation/how-to/terraform-error-handling): missing variables and name mismatches
