logo

Cheatsheet - HCL

HCL (HashiCorp Configuration Language) is a configuration language created by HashiCorp. It's designed to be human-friendly for machine-generated, and provides a structured way to define configurations for tools like Terraform, Vault, Nomad, Consul, and Packer.

It's a superset of JSON, meaning any valid JSON is also valid HCL. However, HCL adds features that make it more readable and flexible for human users.

Basic Syntax & Structure

HCL is built around blocks and arguments.

Arguments: Set a value for a specific name.

# argument_name = value
name = "Terraform"
version = 1.0
enabled = true

Blocks: Define a container for arguments and other nested blocks. Blocks have a type, and optionally one or more labels.

# block_type "block_label1" "block_label2" {
#   argument = value
#   nested_block_type "label" { ... }
# }

resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorld"
    Env  = "Dev"
  }
}

Comments:

  • # This is a single-line comment
  • // This is also a single-line comment
  • /* This is a multi-line comment */

Data Types

HCL supports common data types.

Strings: Enclosed in double quotes. Can use interpolation.

region = "us-east-1"
message = "Hello, ${var.user_name}!"

Numbers: Integers or floating-point numbers.

count = 5
price = 99.99

Booleans: true or false.

ssl_enabled = true

Lists/Tuples: Ordered collections of values.

subnets = ["10.0.1.0/24", "10.0.2.0/24"]

Maps/Objects: Key-value pairs. Keys are strings.

tags = {
  Environment = "Production"
  Owner       = "IT Team"
}

Null: null. Represents the absence of a value.

Expressions

Expressions allow dynamic values and logic.

Literal Expressions: Directly represent a value (e.g., "string", 123, true, ["a", "b"], {key="val"}).

Reference Expressions: Reference a named value.

  • var.name: Access an input variable.
  • resource_type.resource_name.attribute: Access an attribute of a resource.
  • local.name: Access a local value.

Arithmetic Operators: +, -, *, /, %

total_cost = var.num_servers * 50.0

Comparison Operators: ==, !=, <, >, <=, >=

is_prod = var.environment == "production"

Logical Operators: && (and), || (or), ! (not)

condition = var.enabled && (var.mode == "active" || var.mode == "standby")

Conditional Operator (Ternary): condition ? true_val : false_val

instance_type = var.env == "prod" ? "m5.large" : "t3.medium"

Collection Operators:

  • Index Access: list[index], map["key"]
  • Splat Operator (.* and [*]): Transform a list of objects into a list of a specific attribute.
    # If az_list is a list of objects like [{id="a", zone="us-east-1a"}, ...]
    zones = az_list[*].zone # ["us-east-1a", "us-east-1b", ...]
    

Function Calls: function_name(arg1, arg2, ...)

instance_ip = cidrhost("10.0.0.0/16", 5)
lower_case_name = lower("MYAPP")

Common built-in functions often depend on the HCL-consuming tool (e.g., Terraform functions).

Variables & Values (Terraform-centric, but general HCL concept)

While HCL itself is just a language, how variables are defined and used is typically driven by the tool using it. Here's a common pattern from Terraform:

Input Variables (variable block): Define values to be provided to the configuration.

variable "region" {
  description = "AWS region"
  type        = string
  default     = "us-east-1"
}
# Usage: var.region

Local Values (locals block): Define named expressions that can be reused within the configuration.

locals {
  common_tags = {
    Project = "MyProject"
    Env     = var.environment
  }
  full_name = "${var.prefix}-${var.service_name}"
}
# Usage: local.common_tags, local.full_name

Output Values (output block): Define values that are exposed as outputs of the configuration.

output "instance_ip" {
  description = "Public IP of the EC2 instance"
  value       = aws_instance.web.public_ip
}

String Interpolation & Templates

HCL uses ${...} for interpolation within strings.

Simple Interpolation:

server_name = "app-${count.index}"

Conditional Interpolation:

message = "VM running in ${var.env == "prod" ? "Production" : "Development"}."

Dynamic Blocks (HCL2): Create multiple nested blocks based on a collection.

resource "aws_security_group" "example" {
  name = "example"

  dynamic "ingress" {
    for_each = var.ingress_rules
    content {
      from_port   = ingress.value.port
      to_port     = ingress.value.port
      protocol    = ingress.value.protocol
      cidr_blocks = ingress.value.cidr_blocks
    }
  }
}

File Types

  • .hcl: Standard HCL file extension.
  • .tf: Terraform configuration file extension (which uses HCL).
  • .json: HCL can parse JSON, so you can sometimes use .json files for configuration, especially for machine-generated configs.