HCL v2
A Go toolkit for parsing, evaluating, and generating HashiCorp's HCL configuration language.
Repository Health
Technical Analysis
HCL (HashiCorp Configuration Language) v2 is the Go library that Terraform, Packer, Nomad, and Vault use to parse, evaluate, and manipulate their configuration files. It defines a syntax-agnostic information model of attributes and blocks, alongside two concrete syntaxes — a human-friendly native syntax and a machine-generated JSON variant — that both decode into the same underlying data structures.
Beyond the core parser, the module ships a family of subpackages for different levels of control: hclsimple for one-line struct decoding, gohcl for tag-based struct mapping, hcldec for schema-driven decoding into dynamic cty values, hclwrite for programmatically constructing and editing HCL source while preserving formatting, and an ext/ directory with helpers for dynamic blocks, user-defined functions, and type expressions.
What You Get
- A dual-syntax parser (native hclsyntax format and an equivalent JSON representation) that produce the same object model
- hclwrite for round-trip-safe programmatic editing of HCL files without losing comments or formatting
- hclsimple and gohcl for decoding straight into tagged Go structs
- hcldec for schema-driven decoding into cty dynamic values when the configuration shape isn’t known at compile time
- Rich diagnostics with source-range-aware error messages, plus hcled for highlighting them in an editor context
Common Use Cases
- Building a CLI tool’s configuration file format (the exact case for Terraform, Packer, Nomad, and Vault)
- Writing infrastructure-as-code tools that need block-based config with expressions and variable interpolation
- Programmatically generating or rewriting HCL files, such as Terraform module codegen, via hclwrite
- Embedding a small expression language into an existing Go application using the ext/userfunc and ext/tryfunc helpers
Under The Hood
Architecture The module is organized as a syntax-agnostic core (structure.go, ops.go, traversal.go) that defines Body, Block, and Attribute as interfaces, with two independent syntax implementations — hclsyntax (native format, its own lexer/parser/AST) and json (the JSON variant) — that both satisfy the same Body interface and therefore produce identical results for calling code regardless of which syntax was used. On top of this core sit orthogonal decoding layers: gohcl walks Go struct tags via reflection to populate typed values, hcldec takes a runtime-built Spec tree to decode into dynamic cty.Value results, and hclwrite wraps the native syntax AST in a mutable, formatting-preserving API. Diagnostics flow as a first-class hcl.Diagnostics type threaded through every layer rather than Go’s built-in error, letting callers accumulate multiple errors with source ranges before deciding whether to abort.
Tech Stack
Pure Go (module targets Go 1.25), with the zclconf/go-cty package as its dynamic value system (cty.Value, cty/convert, cty/gocty) used throughout the decoding APIs. Supporting dependencies are narrow and specific: agext/levenshtein for “did you mean” suggestions in diagnostics, apparentlymart/go-textseg for correct Unicode grapheme handling in source positions, mitchellh/go-wordwrap for diagnostic text formatting, and golang.org/x/tools for the code-generation step (expression_vars_gen.go) that keeps the variable-walking logic in sync with the AST. No external build tooling beyond go build; a Makefile and golangci-lint config drive CI.
Code Quality Testing is extensive — roughly a third of the module’s ~190 Go files are _test.go files, with unit tests alongside nearly every source file (parser, decoder, and each ext/ subpackage) plus a fuzz/ directory and an integrationtest/ directory for end-to-end scenarios. Error handling is explicit and typed throughout via hcl.Diagnostics rather than swallowed errors or generic panics (panics are reserved for programmer errors like passing a non-pointer to DecodeBody). Naming is consistent and the package boundaries are clean — each concern (parsing, writing, struct decoding, dynamic decoding, editor integration) lives in its own subpackage. CI runs via GitHub Actions (.github/workflows/checks.yml) with golangci-lint configured.
What Makes It Unique HCL’s distinguishing design choice is decoupling the configuration syntax from its semantic model: the same Body interface, and therefore the same calling-application code, works identically whether the source was written in native HCL syntax or generated as JSON, which is what lets tools like Terraform accept both hand-authored and machine-generated configuration without separate code paths. The hclwrite package is also comparatively rare among config-parsing libraries — most parsers are read-only, but hclwrite supports structural editing of existing files (adding attributes, blocks, comments) while preserving the original formatting, which is what powers automated Terraform config generation and refactoring tools.
Used by 5 apps in this directory
Coder
Devops · Developer Tools · Code Editors
Self-hosted cloud development environments and AI coding agents — defined in Terraform, connected via WireGuard, automatically shut down when idle.
Digger
Devops · Automation · Developer Tools
Run Terraform and OpenTofu natively inside your existing CI pipeline — no separate runners, no third-party secrets, no extra compute costs.
Grafana
Monitoring · Analytics
The open-source observability platform that unifies metrics, logs, and traces from any data source into dynamic, queryable dashboards.
infracost
Devops · Developer Tools
Infracost shows cloud cost estimates for Terraform, CloudFormation, and AWS CDK before you deploy — in your terminal, editor, AI coding agent, and pull requests.
Teleport
Security · Authentication
Zero-trust infrastructure access platform that replaces credentials and VPNs with short-lived certificates, SSO, and identity-aware proxies for SSH, Kubernetes, databases, RDP, and AI agents.