
HCL structure and basic syntax
HCL configurations are organized into blocks that group related configuration items. Each block has:- A block type (for example,
resource,data,variable,output) - One or more labels (for example, a resource type and an instance name)
- A body containing arguments and optionally nested blocks
- Single-line comments:
#or// - Multi-line (block) comments:
/* ... */
.tf extension (for example, main.tf). Terraform automatically loads .tf files in a directory as a single configuration.
Common HCL block types (at-a-glance)
| Block Type | Purpose | Example |
|---|---|---|
resource | Declares infrastructure to create and manage | resource "aws_instance" "web" { ... } |
data | Reads information from existing infrastructure | data "aws_ami" "ubuntu" { ... } |
variable | Declares input values for a module | variable "aws_region" { type = string } |
output | Exposes values from a module or root configuration | output "vpc_id" { value = aws_vpc.vpc.id } |
locals | Defines local computed values | locals { common_tags = { Environment = "dev" } } |
A real example: defining a VPC
Below is a compact, realistic Terraform configuration showing data sources and a resource block that defines an AWS VPC:datablocks read existing information (e.g., AZs or AMIs).resourceblocks declare resources Terraform will manage.- Arguments inside resource blocks (like
cidr_block) describe desired properties, not procedural steps.
Use
terraform fmt or a Terraform-aware editor (for example, the VS Code Terraform extension) to keep formatting consistent automatically.Anatomy of a resource block
Breakdown of the VPC resource block:resource— keyword indicating managed infrastructure.- First label (
"aws_vpc") — the resource type provided by the provider (AWS in this case). - Second label (
"vpc") — the local instance name that uniquely identifies this resource in the module. - Body — arguments (like
cidr_block) and nested blocks (liketags) describing the resource.
resource_type.resource_name, for example aws_vpc.vpc. That address allows other resources, modules, and outputs to read attributes from the VPC.
Each resource name (the second label) must be unique per resource type within a module. For multiple VPCs use distinct names, for example:
HCL style recommendations
Consistent style improves readability, collaboration, and long-term maintainability. Common conventions:- Comments: explain intent and rationale (the why), not just what the code does.
- Naming: prefer
snake_case(underscores) for variables, resources, and attributes (for example,vpc_cidr,vpc_name). - Indentation: use two spaces per nesting level (avoid tabs).
- Equals alignment: aligning
=within logical groups makes blocks easier to scan. - Visual grouping: use blank lines to separate logical groups of arguments (for example, networking settings vs tags).
- Use
localsfor shared computed values and avoid duplicating constants.
terraform fmt and editor integrations will enforce many formatting rules automatically. Manual choices such as equals-sign alignment may need editor settings or manual edits.
Never commit secrets (API keys, passwords) directly into
.tf files or version control. Use variables with secure storage backends (for example, environment variables, secret managers, or Terraform Cloud workspaces) to protect sensitive data.Quick workflow (getting started)
- Create
main.tfwith your HCL configuration. - Initialize the working directory:
- See proposed changes:
- Apply changes:
Summary
- HCL is Terraform’s declarative configuration language focused on readability and expressiveness.
- Configurations are composed of blocks (with types, labels, and bodies) that describe resources, data sources, variables, outputs, and locals.
- Follow consistent naming, commenting, and formatting conventions to make configurations easier to maintain.
- Use
terraform fmt, editor integrations, and secure secret management practices to maintain quality and security.
main.tf files, running terraform init, terraform plan, and terraform apply, and incrementally refining your HCL skills.