Mastering tfvars: A Concise Guide for Terraform and OpenTofu

Learn how to structure, secure & reuse tfvars files to streamline Terraform/OpenTofu deployments across environments—complete syntax, tips & tools.

1. Introduction: The Power of tfvars

tfvars files are essential for parameterizing Infrastructure as Code (IaC) with Terraform and OpenTofu. They allow you to supply input variable values, enabling customization for different environments (dev, prod) or configurations without altering core infrastructure code. This separation promotes reusability, maintainability, and a clear distinction between configuration values and logic. The principles discussed apply to both Terraform and OpenTofu, which is designed as a drop-in replacement.

2. Defining Variables and Assigning Values

  • Variable Declaration (variables.tf): Variables are declared in .tf files (commonly variables.tf) using variable blocks. Key arguments include:
    • type: Specifies data type (e.g., string, number, list, map, object).
    • description: Documents the variable's purpose.
    • default: Provides a default value, making the variable optional.
    • validation: Defines custom rules for the variable's value.
    • sensitive = true: Redacts the value from CLI output (but not from the state file).
  • Value Assignment (.tfvars files): tfvars files assign values to declared variables.
    • Syntax: HCL (variable_name = "value") in .tfvars files, or JSON in .tfvars.json files.

Example (terraform.tfvars):

instance_type = "t2.medium"
aws_region    = "us-east-1"

3. How Variables are Loaded

Terraform and OpenTofu load variables from tfvars files in specific ways:

  • Automatic Loading:
    • terraform.tfvars or terraform.tfvars.json: Loaded automatically if present in the root module directory. Used for base/default values for a working copy.
    • *.auto.tfvars or *.auto.tfvars.json: Any files with these extensions are loaded automatically in lexical (alphabetical) order of their filenames. Useful for segmenting variables or user-specific overrides (often gitignored).
  • Explicit Loading (-var-file option):
    • The -var-file="custom.tfvars" command-line option explicitly loads a specified tfvars file. Essential for environment-specific configurations (e.g., tofu apply -var-file="production.tfvars"). Multiple files can be specified and are loaded in order.
  • Scope: Values from tfvars files apply only to variables declared in the root module.

4. Variable Precedence: The Order of Overrides

If a variable is defined in multiple places, the last one loaded takes precedence. The order (from lowest to highest precedence) for CLI workflows is:

  1. Environment Variables: TF_VAR_name (or OPENTOFU_VAR_name for OpenTofu, which takes precedence if both are set).
  2. terraform.tfvars file.
  3. terraform.tfvars.json file (if both this and terraform.tfvars exist, JSON usually overrides for the same variable).
  4. *.auto.tfvars or *.auto.tfvars.json files (loaded alphabetically; later files override earlier ones).
  5. Command-line flags (-var and -var-file): Processed in the order given; later flags override earlier ones. These have the highest precedence.

Understanding this hierarchy is crucial for debugging.

5. tfvars in Action: Examples

Simple Values (dev.tfvars):

instance_count    = 2
enable_monitoring = false
environment_name  = "development"

Complex Types (List of Objects in services.tfvars): Assuming variables.tf defines app_services as list(object({ name=string, instance_type=string, port=number })):

// services.tfvars
app_services = [
  { name = "frontend", instance_type = "t3.medium", port = 80 },
  { name = "backend", instance_type = "t3.large", port = 8080 }
]

This is powerful with for_each or count to dynamically create resources.

Environment-Specific Configurations: Use separate files like dev.tfvars and prod.tfvars, loaded via -var-file, to manage different settings (e.g., instance types) for each environment.

6. OpenTofu and tfvars: Key Points

  • Compatibility: OpenTofu is largely a drop-in replacement for Terraform, maintaining compatibility with tfvars handling (syntax, loading, naming).
  • Official Documentation: Refer to OpenTofu's official docs for specifics.
  • Environment Variables: OpenTofu honors TF_VAR_ for backward compatibility but introduces OPENTOFU_VAR_. If both are set for the same variable, OPENTOFU_VAR_name prevails. Adopting OPENTOFU_ prefixes is recommended for new OpenTofu projects.

7. Best Practices for tfvars Management

  • Multiple Environments:
    • Use distinct files for each environment (e.g., development.tfvars, production.tfvars).
    • Load explicitly with -var-file.
    • Organize in a dedicated directory (e.g., tfvars/ or environments/).
  • Security First: Handling Sensitive Data:
    • Golden Rule: Never commit plain-text secrets to version-controlled tfvars files.
    • Alternatives:
      • Environment Variables: Injected by CI/CD or set locally (use with care).
      • Secrets Management Tools: HashiCorp Vault, AWS/Azure/GCP Secret Manager. Fetch secrets at runtime.
      • IaC Platforms: Terraform Cloud, Spacelift offer secure variable storage.
      • Encryption: Tools like Mozilla SOPS can encrypt values within files.
    • sensitive = true: In variables.tf, this redacts values from CLI output but does not encrypt them in the state file. Secure your state file (e.g., remote backend with encryption).
  • Version Control (.gitignore):
    • Commit example tfvars files (e.g., terraform.tfvars.example).
    • Add actual tfvars files containing secrets or environment-specifics to .gitignore.
  • Clarity and Maintainability:
    • Use clear naming conventions for files and variables.
    • Thoroughly document variables in variables.tf using description.
    • Maintain consistency across projects.

8. Advanced Techniques

  • Programmatic Generation:
    • terraform-docs: Can generate template tfvars files.
    • Custom Scripts (Shell, Python): Fetch data from external sources (CMDBs, APIs) to build tfvars.
  • CI/CD Integration:
    • Store/generate tfvars securely within CI/CD.
    • Use -var-file or environment variables (TF_VAR_/OPENTOFU_VAR_) in pipelines.
  • Workspaces: Use workspace-named tfvars (e.g., dev.tfvars) selected dynamically: terraform plan -var-file="${TERRAFORM_WORKSPACE}.tfvars".

9. Troubleshooting Common Pitfalls

  • "Undeclared Variable": Variable assigned in tfvars but not declared in .tf files. Check for typos and ensure declaration.
  • File Loading/Naming Issues: Incorrect filenames (e.g., terraform.tfvar) or location (not in root module). Verify names and paths.
  • Precedence Misunderstanding: Unexpected values due to overrides from higher-precedence sources. Review the precedence order.
  • Syntax Errors: Invalid HCL or JSON in tfvars files. Validate syntax carefully.
  • Sensitive Data Exposure: Secrets in version control or state files. Rotate compromised secrets immediately. Implement proper secrets management and .gitignore rules.
  • Type Mismatches: Value in tfvars doesn't match type in variable declaration. Ensure values adhere to defined types.

10. Conclusion: Effective Infrastructure Customization

tfvars files are crucial for customizing Terraform and OpenTofu configurations. Mastering their use involves understanding variable declaration, loading mechanisms, precedence, and, critically, security best practices. By avoiding plain-text secrets in version control and adopting robust management strategies, teams can build flexible, secure, and maintainable IaC, enabling efficient management of complex environments.