linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
home/terraform/kb/Variables & outputs/tf-variable

kb/variables ── Variables & outputs ── beginner

The variable block: input to your configuration

A variable is a parameter that receives its value from outside the configuration (CLI, environment variable, .tfvars file). You declare it in HCL with type, default, description, and validation, then reference it as var.name. Variables remove hardcoded values and let one HCL configuration serve multiple environments.

view as markdown

Why variables exist

Without variables, each environment needs its own HCL file. With variables, one HCL file handles multiple environments through separate value sets.

Without variables:

hcl
resource "aws_s3_bucket" "demo" {
  bucket = "my-app-prod-logs"  # hardcoded
}

With variables:

hcl
variable "env" {
  type    = string
  default = "dev"
}
resource "aws_s3_bucket" "demo" {
  bucket = "my-app-${var.env}-logs"
}

Now the same HCL runs with -var="env=prod" for production, with no code changes.

A minimal variable

hcl
variable "bucket_name" {}

This is a valid variable. No type is declared (defaults to any), no description, no default, so you must supply a value from outside. If you omit it, apply fails with a prompt.

All variable fields

hcl
variable "bucket_name" {
  type        = string                          # expected type (see below)
  description = "S3 bucket name. Must be globally unique."
  default     = "my-default-bucket-12345"       # used when no external value is set
  nullable    = false                           # disallow null (default true)
  sensitive   = false                           # mark to hide from log output
  ephemeral   = false                           # in-memory only, not written to state (1.10+)
  validation {
    condition     = length(var.bucket_name) >= 3 && length(var.bucket_name) <= 63
    error_message = "Bucket name must be between 3 and 63 characters."
  }
  validation {
    condition     = can(regex("^[a-z0-9][a-z0-9.-]*[a-z0-9]$", var.bucket_name))
    error_message = "Bucket name: lowercase letters, digits, dots, and hyphens only."
  }
}

Not all fields are required. At minimum you need type and, when there is no default, a value supplied from outside.

Variable types

Variables accept primitive and complex types:

hcl
# primitives
variable "region" { type = string }
variable "count"  { type = number }
variable "enabled" { type = bool }
# collections
variable "tags"   { type = map(string) }
variable "azs"    { type = list(string) }
variable "values" { type = set(string) }   # unique, unordered
# object (like map, but with a fixed structure)
variable "db" {
  type = object({
    instance_class    = string
    allocated_storage = number
    multi_az          = bool
  })
}
# no type constraint, anything is accepted (poor practice for production)
variable "anything" {}

If a value does not match the declared type, Terraform fails with a clear error. See hcl-types.

Validation: correctness checks

Conditions that Terraform checks before using a variable:

hcl
variable "env" {
  type        = string
  description = "Environment (dev/staging/prod)"
  validation {
    condition     = contains(["dev", "staging", "prod"], var.env)
    error_message = "env must be one of: dev, staging, prod."
  }
}

Validation runs at plan time. If condition returns false, apply does not start, and Terraform shows the error_message.

You can add multiple validation blocks to one variable. All of them are checked.

sensitive: protection from log output

hcl
variable "db_password" {
  type      = string
  sensitive = true
}

Effect:

  • In plan and apply output, the value is replaced with (sensitive value).
  • Any output that references this variable is also masked (unless the output is explicitly marked sensitive on its own).
  • The state file still stores the value in plain text. sensitive affects CLI output, not encryption.

For real secrecy, use Vault, AWS Secrets Manager, or at minimum an encrypted remote state with restricted access.

Using a variable

hcl
variable "env" {
  type    = string
  default = "dev"
}
resource "aws_s3_bucket" "demo" {
  bucket = "my-app-${var.env}-bucket"
  tags = {
    Environment = var.env
  }
}

The var. prefix is required. Without it, Terraform treats the name as a resource or data reference.

Common pitfalls

  • Always declare a type. Omitting it works, but type errors only surface late. A type annotation catches the problem at validation time.

  • default is not a fallback value. It is the value used when nothing is supplied from outside. When an external value is present, default is ignored.

  • sensitive is not encryption. It masks output in the CLI. In state, the value is stored in plain text.

  • Variables cannot reference each other. variable "b" { default = var.a } is invalid. For dependent expressions, use tf-locals.

  • Validation only runs at plan time. When a value comes from a data source and is "known after apply", validation may miss the error.

  • Variables are global to the configuration. There are no block-scoped variables. When you need a local expression, use locals { ... }.

§ команды

bash
terraform plan -var='env=prod'

Pass a variable value from the CLI. You can use multiple -var flags.

bash
terraform plan -var-file=prod.tfvars

Load all variables from a file. See [[tf-tfvars]] for the file format.

bash
TF_VAR_env=prod terraform plan

Pass a value through an environment variable. The prefix is TF_VAR_ followed by the variable name.

§ см. также

  • tf-variable-sourcesWhere Terraform reads variable values fromSix sources, in priority order: -var in CLI > -var-file > *.auto.tfvars (alphabetically) > terraform.tfvars > TF_VAR_* env > default. If none of these supply a value, Terraform prompts interactively. Understanding this order matters for CI/CD.
  • tf-tfvars.tfvars: variable value files.tfvars files hold variable values in HCL or JSON format. terraform.tfvars and *.auto.tfvars are loaded automatically; all others require -var-file. This is the main mechanism for separating code from environment configuration.
  • hcl-typesData types in HCL: string, number, list, map, objectHCL supports primitives (string, number, bool) and complex types: list, set, map, tuple, object. This article covers the syntax of each one and the difference between the look-alikes (list vs tuple, map vs object).
  • tf-outputThe output block: what Terraform exposes to the outsideAn output is a value that Terraform displays after apply and stores in state. Use it to (a) show the user the ID or ARN of a created resource, (b) pass values between modules, or (c) feed values to scripts via `terraform output -raw`.
  • tf-localslocals: computed internal nameslocals is a block with names visible only inside HCL (not input, not output). Useful for DRY: compute a common prefix or tag set once, then use it everywhere via local.x. Do not confuse with variable (input) and output (output).
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies