Terraform
Beginner 16 min read Terraform

HCL: Resources, Variables & Outputs

HCL is the declarative language Terraform is written in. Master resource blocks, variables, locals, data sources and outputs to parameterize and reuse configurations.

HCLresourcesvariablesoutputslocalsdata sourcessensitiveexpressions
Introduction

What is this?

HCL (HashiCorp Configuration Language) is Terraform's declarative syntax. Everything is built from blocks and arguments. Resource blocks create and manage objects, data sources read existing objects, variables parameterize inputs, locals compute reused expressions, and outputs publish results after apply.

Motivation

Why do you need it?

  • Variables turn one configuration into many environments without copy-paste.
  • Outputs expose IPs, IDs and ARNs for use by other tools and modules.
  • Data sources read existing infrastructure without managing or destroying it.
  • References and functions wire resources together and keep configuration DRY.
  • The sensitive flag keeps passwords and keys out of apply output and logs.
Think about it

Mental model

Imagine

A recipe with blank ingredient amounts

Think of

A Terraform configuration with variables

The same recipe card can make a different batch size by filling the blanks differently. The same .tf files produce different infrastructure per environment by supplying different variable values.

Mechanics

How it works

  • resource blocks declare objects you own, for example resource "aws_instance" "web" { ... }.
  • Arguments inside the block set desired attributes; references like aws_vpc.main.id wire resources together.
  • variable blocks define typed inputs with defaults, descriptions and validation.
  • locals compute values once and reuse them throughout the configuration.
  • data blocks query existing objects, for example data "aws_ami" "ubuntu" { ... }.
  • output blocks publish values after apply, optionally marked sensitive.

Data flow through HCL block types.

Variables
Locals
Resources
Data sources
Outputs
Reference

Key commands

terraform console

Open an interactive shell to evaluate expressions and references against your config.

terraform fmt

Reformat HCL to canonical style.

terraform validate

Check configuration validity without contacting providers.

terraform plan -var 'username=bob'

Override a variable value for a single run.

terraform show

Display the current state or a saved plan in human-readable form.

terraform providers

List the provider plugins required by the configuration.

Hands-on

Examples

Variables, locals and outputs working together

Variables, locals and outputs working together
variable "username" {
type = string
default = "alice"
}
variable "greeting_file" {
type = string
default = "./greeting.txt"
description = "Path where the greeting file is written"
}
locals {
message = "Hello, ${var.username}!"
}
resource "local_file" "greeting" {
content = local.message
filename = var.greeting_file
}
output "greeting_content" {
value = local.message
description = "The message that was written to the file"
}

The variables parameterize the config, the local computes the message once, the resource uses both, and the output publishes the result. Override values with a terraform.tfvars file or -var at the CLI.

Real world

In production

  • Environment-specific values flow in via terraform.tfvars, .tfvars.json or CI/CD variables.
  • Sensitive variables (passwords, API keys) are marked sensitive and never printed.
  • Outputs feed downstream tools: scripts, CI steps and terraform_remote_state consumers.
  • Data sources fetch the current AMI, subnet or DNS zone so nothing is hardcoded.
Guidelines

Best practices

  • Declare types, defaults and descriptions for every variable.
  • Use locals for any expression used more than once.
  • Mark secrets sensitive = true and inject them from environment or secret stores.
  • Reference other resources by attribute, never by hardcoded ID.
  • Group related variables into variables.tf, outputs into outputs.tf, resources into main.tf.
Watch out

Common mistakes

  • Hardcoding IDs and values instead of referencing resources or data sources.
  • Using dashes or leading digits in resource names, which are invalid identifiers.
  • Missing sensitive = true on secrets, leaking them into state and logs.
  • Storing real variable values inside the config instead of tfvars files.
Root cause analysis

Common issues

Error
Error: Invalid resource name
Root cause

The resource name starts with a number or contains a dash.

Fix

Use identifiers starting with a letter, containing only letters, digits and underscores.

Error
Error: Unsupported argument
Root cause

The attribute name does not exist for this resource type.

Fix

Check the provider documentation for the exact argument name, and confirm with terraform validate.

Error
Error: Reference to undeclared resource
Root cause

An expression references a resource that does not exist in the configuration.

Fix

Define the resource, or read it with a data source, before referencing its attributes.

When things break

Debugging tips

  • terraform console lets you test an expression like aws_vpc.main.id before applying.
  • terraform validate catches unknown attributes and invalid references early.
  • terraform fmt --check in CI fails the build on unformatted HCL.
  • When a value looks wrong, print it with a temporary output block or terraform show.
Interviews

Interview checkpoint

Practice

Hands-on lab

Parameterize a Configuration with Variables
30 min ยท beginner
In progress
Objectives
  • Declare typed variables with defaults
  • Pass values via tfvars files and -var flags
  • Use locals and output blocks
  • Mark a sensitive value and observe redaction

Parameterize a Configuration with Variables

30 min ยท beginner

0/5 steps
0%
sandbox ยท Linux sandbox
$
Try these commands
Test yourself

Quick quiz

0/3
1

Which block type reads an existing object without managing it?

2

What is the purpose of an output block?

3

Marking a variable sensitive = true encrypts its value inside the state file.

Quick reference

Cheat sheet

HCL building blocks
resource "type" "name" {}Create and manage an object
data "type" "name" {}Read an existing object
variable "name" {}Declare a typed input
output "name" {}Publish a result after apply
locals { name = ... }Compute a reusable value
var.fooReference a variable
resource.x.attrReference an attribute
Input methods
-var 'k=v'CLI override
terraform.tfvarsAuto-loaded default file
*.auto.tfvarsAuto-loaded named file
env var TF_VAR_nameEnvironment variable input
Go deeper

Official documentation