Hashicorp Configuration Language
Hashicorp Configuration Language is the configuration language developed by Hashicorp, the company behind popular software such as Terraform, Vault, Consul, and Nomad. Hashicorp Configuration Language is used in definitions of infrastructure, policies, and other configurations to be applied in Hashicorp tools.
HCL is a human-readable, declarative language and is intended to define the desired state of the configuration rather than to document step-by-step how that state would be achieved. As such, it is easier for people to write and understand HCL configurations than with more imperative languages. HCL consists of four major syntax constructs
- Arguments
- Blocks
- Identifiers
- Comments
Arguments
syntax
The syntax for an argument in HCL is as follows:
key = value
This is how it operates:
key
is the name assigned for an argument, which denotes a specific setting or property. Ideally, keys should use naming conventions that HCL has provided, where mostly keys use only lowercase letters, digits, and underscore characters.
=
symbol is used to assign a value to the argument.
For example, in your Terraform configuration, you may have an argument that looks something like this:
repository = "codeartifact-repository-name"
In this case, the key is repository which is typically the name of the repository and the value is "codeartifact-repository-name" which is a string.
All the arguments declared in your HCL configurations are used throughout your infrastructure configurations. They define the desired state of your cloud resources, modules or other entities. That way, they provide a declarative means of describing settings of their configurations, making them amenable to management by Terraform or other HCL-based tools.
Blocks
Blocks in Terraform are the basic building blocks of a configuration. It is essentially a way of grouping related configuration elements in Terraform and acts as a container to hold other content, such as arguments and nested blocks.
syntax
Syntax to use a block in HCL is as follows :
block_type label1 label2 ... {
# argument
# nested blocks
}
This is how it operates:
- A
label
is used to give a unique identification to every block instance in a Terraform configuration. The number of labels depends on the kind of block type that one is using. For example, a resource kind of block will require two labels, while the variable kind of block will require only one label.
{ }
is the block body. This is where you define configuration in the block, including its arguments and nested blocks.
Let's take the following resource terraform block as an example.
resource "aws_instance" "example" {
ami = "0123456789"
instance_type = "t2.micro"
network_interface {
subnet_id = "subnet-0123456789"
security_groups = ["sg-0123456789"]
}
}
In this case:
- block_type is resource.
- These include two labels: the first one is "aws_instance," the second one is "example".
- Inside the block body are two arguments: ami and instance_type.
- There is also a nested block of type network_interface with its own set of arguments.
There are various block types that are utilized for the organization as well as structuring of Terraform configuration files. Each type of block has its own specific purpose and is used to define infrastructure as well as manage it. The most common blocks in Terraform include
Identifiers
Identifiers are the names of various elements in the configuration in Terraform. Such names are argument names, block type names, and the names of most Terraform-specific constructs such as resources, input variables, among others.
Terraform identifiers can consist of the following characters:
- Letters (both uppercase and lowercase)
- Digits, 0 through 9, but a leading digit cannot be used for an identifier because of possible ambiguity with a literal number.
- Underscores (
_
)
- Hyphens (
-
)
Here are some examples of valid and invalid identifiers:
- Valid Identifiers: my_resource, my-custom-block, MyModule
- Invalid Identifiers: 1_invalid_identifier, invalid-identifier!, invalid identifier
variable "my_input_variable" {
description = "tell something about your input variable."
type = string
default = "default value"
}
resource "aws_instance" "example" {
ami = "0123456789"
instance_type = "t2.micro"
network_interface {
subnet_id = "subnet-0123456789"
security_groups = ["sg-0123456789"]
}
}
module "my-custom-module" {
source = "./path/to/module"
module_input = var.my_input_variable
}
Here are the identifiers used:
- my_input_variable: valid name for an input variable.
- my_ec2_instance: valid name for a resource.
- my-custom-module: valid module name.
Comments
Comments are a crucial component of any configuration management tool since they provide the ability to describe and document your infrastructure code. Terraform has three styles of writing comments in the configuration files:
Single-line comments with #
Comments that start with the
#
character are carried up through the end of line. It is the default and most commonly used commenting in Terraform.
Example
# This is a single-line comment
instance_type = "m7gd.8xlarge"
The # symbol is recognized by Terraform as the starting point of a comment and the rest of the line will be ignored by the parser. Commenting style is quite known and very recommended in the Terraform community.
Single-line comments using //
Terraform also supports using the
//
syntax to begin a single-line comment. It is a further alternative to the # style but the # style is really preferred.
Example
// This is also a single-line comment
source = "../../ec2/"
The // characters are considered a line comment starter. Whatever left on the line is ignored as a result of it. This style is supported but it's not very common and is also not the idiomatic way for Terraform configurations.
Multi-line comments using /* */:
To write a comment that spans multiple lines, you can make use of the delimiters
/*
and */
. Any text enclosed between these delimiters is considered as a comment and is ignored by the Terraform parser. This style of commenting proves useful when you wish to provide more elaborate explanations or comments that just cannot be said in a line.
Example
/* This is a
multi-line
comment */
region = "us-west-1"
NOTE: The
#
single-line comment style is the default and preferred style of comments in Terraform. Automatically formatting tools for Terraform configuration files, such as terraform fmt
, automatically replace //
comments with #
comments since the double-slash style is not idiomatic for configurations in Terraform.
Configuration Formats
Hashicorp Configuration Language, HCL provides two different formats of configurations wherein users can use any format that suits them the most and their preferences are
- Native format
- Json format
Native syntax
The Native format of HCL is a human-readable domain-specific language. Its syntax is similar to JSON but much more concise and intuitive, making it much easier to write and understand.
Native format is the preferred way to specify infrastructure, policies, or other configurations in Hashicorp tools such as Terraform. Here is a demonstration of a Terraform configuration, where it has demonstrated using Native Format:
resource "aws_security_group" "example" {
name = "Example Security Group"
vpc_id = aws_vpc.example.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
JSON format
HCL also supports a JSON-based format aside from native format. The JSON format is a direct translation of the native HCL format into a JSON representation.
This format comes in handy if you want to programmatically generate or manipulate HCL configurations because JSON is an extremely widely-supported data format. Here is an example of a Terraform configuration showing the usage of Json Format:
{
"resource" : {
"aws_security_group" : {
"example" : {
"name" : "Example Security Group",
"vpc_id" : "${aws_vpc.example.id}",
"ingress" : [
{
"from_port" = 80
"to_port" = 80
"protocol" = "tcp"
"cidr_blocks" = ["0.0.0.0/0"]
}
],
"egress" : [
{
"from_port" = 0
"to_port" = 0
"protocol" = "-1
"cidr_blocks" = ["0.0.0.0/0"]
}
]
}
}
}
}
The choice between the two depends on personal preference and specific use cases. Native HCL format would usually be preferred for a manual configuration management since it is more directly readable by humans than its JSON format counterpart. JSON format is much better suited for automated or programmatic workflows where the configuration needs to be generated or manipulated programmatically.
Related Pages
Feedback
Was this page helpful?