Est. 2014 Beginner

HCL

HashiCorp Configuration Language — a declarative, JSON-interoperable configuration syntax designed for human authoring and machine processing, used by Terraform, Packer, Nomad, Vault, and Consul.

Created by Mitchell Hashimoto (HashiCorp)

Paradigm Declarative, Configuration
Typing Dynamic, with structural schemas defined by host applications
First Appeared 2014
Latest Version hashicorp/hcl v2 library, with releases ongoing in the v2.x series (HCL2 syntax stable since 2019)

HCL (HashiCorp Configuration Language) is a declarative configuration language created by HashiCorp to sit in the middle ground between machine-friendly formats like JSON and human-friendly formats like YAML. It is the surface language for Terraform, Packer, Nomad, Vault, Consul, Waypoint, and Boundary, making it one of the most widely written configuration languages in modern cloud infrastructure work.

History and Origins

HCL was introduced in 2014 by Mitchell Hashimoto and HashiCorp as part of the initial release of Terraform. HashiCorp’s earlier tools, such as Vagrant, used Ruby DSLs for configuration; with Terraform, the team wanted a syntax that was easier to author by hand than JSON, easier to parse and validate than YAML, and friendly to programmatic generation by other tools.

The original HCL — sometimes retroactively called HCL1 — was a fairly simple structural language: blocks, attributes, and a small set of literal types. Expressions were limited, and complex logic was typically performed via interpolation strings ("${var.foo}"). The Go implementation was published under the Mozilla Public License 2.0 in the hashicorp/hcl repository.

By 2017, the limits of HCL1 had become evident. Terraform users were writing increasingly elaborate configurations and bumping into expression-language limitations, awkward type coercions, and gaps in error reporting. HashiCorp engineer Martin Atkins led the design of HCL2, a major redesign that:

  • replaced the ad-hoc interpolation language with a first-class expression sub-language,
  • added explicit types, structural type inference, and for-expressions,
  • formalized the structural-language / expression-language split with a written specification,
  • improved diagnostics with source-range tracking.

HCL2 shipped to end users with Terraform 0.12 in May 2019, the largest single language change in Terraform’s history. Over the following years, the rest of HashiCorp’s product line migrated their configuration surfaces to HCL2 as well.

Design Philosophy

HCL is intentionally a narrow language. Its goals, paraphrased from the official specification, are:

  • Human-friendly structure — blocks, attributes, and comments that read naturally and can be edited without a parser in the loop.
  • Machine-friendly equivalence — every HCL document has an equivalent JSON form, so the same configuration can be authored by humans in .tf or generated by programs in .tf.json.
  • Embeddability — HCL is a library, not an application. Host programs define their own schemas (which blocks and attributes are valid, what types they expect) and HCL handles parsing, decoding, and diagnostics.
  • Separation of structural and expression languages — the structural layer (blocks, attributes, labels) is small and stable; the expression layer is richer and where new features tend to land.

The split between structural and expression languages is what distinguishes HCL from both JSON (no structural sugar, no expressions) and full programming languages (where structure and computation are intertwined). It is also why two different tools can use HCL but expose very different expression semantics — Terraform’s functions, Packer’s functions, and Nomad’s job-spec semantics are layered on top of the shared HCL2 expression grammar.

Key Features

Blocks, Attributes, and Labels

HCL’s structural primitives are blocks (named containers, optionally with labels) and attributes (name = value pairs):

1
2
3
4
5
6
7
8
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"

  tags = {
    Name = "web-server"
  }
}

The host application (Terraform, in this case) defines that resource is a block type that takes two labels, and that within it the ami attribute is a required string.

JSON Equivalence

Every HCL document has a JSON representation. Terraform recognizes .tf.json files alongside .tf files for exactly this reason: machine-generated configurations can be emitted as JSON without losing fidelity, and HashiCorp’s tools accept both interchangeably.

First-Class Expressions (HCL2)

HCL2 expressions include arithmetic, conditionals (cond ? a : b), splat operators, for-expressions over collections, and function calls. Unlike HCL1’s string-interpolation model, expressions are first-class values that can be assigned to attributes directly:

1
2
3
4
locals {
  azs           = ["us-east-1a", "us-east-1b", "us-east-1c"]
  instance_tags = { for i, az in local.azs : "node-${i}" => az }
}

Typed Values via cty

HCL2’s value model is implemented by a companion library, zclconf/go-cty, which provides a small set of primitive types (string, number, bool), collection types (list, set, map), structural types (object, tuple), and a dynamic type. Host applications use cty schemas to describe the values they expect, and HCL2’s decoder converts parsed expressions accordingly.

Diagnostics with Source Ranges

A practical strength of HCL2 is its diagnostic system: parsing and decoding errors come with precise source ranges, enabling tools like terraform fmt and language servers to point users at the exact byte range of a problem. This is why Terraform error messages can underline the offending sub-expression in a complex line.

Implementations

HCL has effectively one reference implementation: the Go library at github.com/hashicorp/hcl, currently in its v2 module. This is the parser used by every official HashiCorp tool and by the OpenTofu fork.

Third-party HCL parsers exist in several languages — there are community parsers in Python, Rust, and JavaScript — but none has the status of an alternate reference, and they typically lag the Go library on newer syntax features. Because the HCL2 specification is published in the same repository as the Go implementation, in practice the Go code is the source of truth.

Specification and Licensing

HCL2 has a written specification at github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md, covering both the native syntax and the JSON-equivalent syntax. The specification is sufficient to write an interoperable parser, though in practice ecosystem alignment around the Go library means most new tools simply consume the Go library directly.

The hashicorp/hcl library is licensed under the Mozilla Public License 2.0, an OSI-approved license that pre-dates HashiCorp’s 2023 relicensing of products like Terraform under the Business Source License (BSL). The HCL library itself was not affected by that license change, which is why the OpenTofu fork of Terraform can continue to consume it.

Current Relevance

As of 2026, HCL is among the most widely written configuration languages in cloud infrastructure work. Terraform’s continued popularity — together with that of OpenTofu — means HCL is the day-to-day language for a large share of platform and DevOps engineers. Packer, Nomad, Vault, and Consul broaden HCL’s reach beyond infrastructure provisioning into image building, workload scheduling, secrets management, and service networking.

HCL is not a general-purpose language and is unlikely to escape the configuration niche. Within that niche, however, its combination of human-readable structure, JSON equivalence, and embeddable Go implementation has made it the de facto standard for HashiCorp-adjacent tooling and the closest thing the cloud-native ecosystem has to a shared declarative configuration language outside of YAML.

Why It Matters

HCL is a useful counterexample in the long-running debate about whether configuration should be data (JSON, YAML, TOML) or code (Python, Ruby, JavaScript DSLs). HCL’s bet is that neither answer is quite right: configuration deserves a small dedicated language whose syntax is shaped by human authoring concerns, whose values can be losslessly serialized as data, and whose expression semantics are owned by the host application rather than the language itself.

That bet has paid off in practice. The success of Terraform alone has made HCL one of the most-read and most-written configuration formats of the 2020s, and its design has informed how the rest of the industry thinks about declarative-but-programmable configuration.

Timeline

2014
HCL introduced by HashiCorp alongside the initial release of Terraform (v0.1, July 2014); the hashicorp/hcl Go library is published as open source under MPL 2.0
2014
HCL adopted as the configuration syntax for additional HashiCorp tools, including Packer and the early Nomad and Consul codebases
2017
Work begins on HCL2, a major redesign that unifies the structural language with a richer expression sub-language and a formal specification
2018
HCL2 enters wide preview through Terraform 0.12 development; the hashicorp/hcl2 repository hosts the new implementation before being merged back into hashicorp/hcl as the v2 module
2019
Terraform 0.12 released in May, making HCL2 the default surface syntax for Terraform users and introducing first-class expressions, for-expressions, conditionals, and a typed expression model
2020
HCL2 stabilizes as the standard across HashiCorp's product line; Waypoint launches in October 2020 using HCL for application configuration
2021
Boundary and other HashiCorp tools continue standardizing on HCL2 for their configuration formats
2023
HashiCorp re-licenses many of its flagship products from MPL 2.0 to the Business Source License (BSL); the hashicorp/hcl library itself remains under MPL 2.0, and the OpenTofu fork of Terraform continues consuming HCL
2024
HCL continues to receive regular releases in the v2.x series; the Linux Foundation's OpenTofu project, which uses HCL, reaches general availability in January

Notable Uses & Legacy

Terraform

HashiCorp's infrastructure-as-code tool is the most prominent consumer of HCL. Terraform configurations declare providers, resources, data sources, variables, and outputs in `.tf` files written in HCL2.

Packer

HashiCorp's image-building tool uses HCL to declare builders, provisioners, and post-processors. Packer migrated from a JSON-only configuration format to HCL2 as the recommended format starting with Packer 1.5.

Nomad

HashiCorp's workload orchestrator uses HCL for job specifications, which describe groups, tasks, networking, and constraints for cluster scheduling.

Vault and Consul

HashiCorp's secrets-management and service-networking products use HCL for their server configuration files and for policy definitions (e.g., Vault ACL policies, Consul intentions).

OpenTofu

The Linux Foundation's open-source fork of Terraform, created in response to HashiCorp's 2023 BSL license change, continues to consume HCL configurations and depends on the hashicorp/hcl library.

Waypoint and Boundary

Other HashiCorp tools that adopted HCL as their configuration language — Waypoint for application build/deploy/release pipelines, Boundary for identity-based remote access configuration.

Language Influence

Influenced By

libucl nginx configuration JSON

Running Today

Run examples using the official Docker image:

docker pull hashicorp/terraform:latest

Example usage:

docker run --rm -v $(pwd):/work -w /work hashicorp/terraform:latest fmt
Last updated: