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)
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
.tfor 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):
| |
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:
| |
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
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
Running Today
Run examples using the official Docker image:
docker pull hashicorp/terraform:latestExample usage:
docker run --rm -v $(pwd):/work -w /work hashicorp/terraform:latest fmt