HCL is for designing a language, not loading a settings file
HCL starts to make sense when a product needs its own vocabulary. The application declares which attributes and nested blocks are valid, then HCL parses the file against that structure and returns values plus diagnostics. A server might accept a service block with protocol labels and nested process blocks. That is more expressive than decoding a generic map, and more work than reading a TOML file into a struct.
The choice should follow the product, not Terraform's familiarity. If users only set a port, log level, and database URL, HCL adds syntax decisions they do not need. If they describe resources, policies, jobs, or relationships, named blocks and labels can make the file match the problem. Your team still owns the resulting language: allowed names, evaluation context, error messages, compatibility, and documentation.
One model accepts native HCL and JSON
HCL has a native syntax for people and a JSON representation for software that generates files. Both forms map into the same attributes-and-blocks model. That gives a tool a hand-edited format without forcing an automation system to print native syntax. JSON strings can also contain interpolation expressions, so generated input can reach the same evaluator when the application permits it.
Expressions are not an unrestricted program hidden inside the file. HCL supplies parsing and evaluation machinery, while the calling application decides which variables and functions exist. This boundary is useful for a domain-specific language because the host can expose upper() or a resource reference without embedding a general-purpose runtime. It also creates an API-design duty: an expression valid in one HCL-based product may be meaningless in another.
What happened when we ran it
Our sandbox installed commit 4c31772 in 93 seconds and fetched 22 packages. The build completed in 32 seconds. Testing took another 23 seconds, with 36 passed and 0 failed out of 36. The fresh Debian container had 3 CPUs, 8 GB of RAM, Go 1.24, no credentials, and no elevated privileges.
The checkout contained 379 files, about 66,546 lines of source, and occupied 2.2 MB. Our scan found 2 CI workflow files, no Dockerfile, and no tests directory. A Dockerfile is unnecessary for a Go library, and the passing test command matters more than a directory name. The result is a small checkout with a modest dependency count and a clean build-and-test path.
These numbers cover repository mechanics. They do not measure parser throughput, memory use on large files, diagnostic quality for your schema, or the cost of evaluating expressions. We did not invent a sample language and benchmark it. HCL passed the supplied 36-test run; a buyer still needs fixtures drawn from the configuration its own users will write.
The simple decoder and lower-level APIs serve different jobs
The README's short example uses hclsimple.DecodeFile and Go struct tags. That route works when the file shape is known and the program wants typed values. HCL also exposes lower-level parsing, content selection, decoding, and evaluation for editors, partial configuration, or tools that need to keep working after a user makes a syntax mistake. Start with the simple path unless a concrete feature requires more control.
Writing and refactoring deserve separate tests. Release v2.25.0 added comment accessors and setters for attribute and block changes in hclwrite. Open issue 840 reports that variable discovery and prefix renaming miss traversals inside certain object values after a recent change. Issue 844 reports an error from JustAttributes after PartialContent hides a nested block. If your product edits users' files, round-trip fixtures should cover every expression shape it rewrites.
HCL 2 is a separate Go API, not an HCL 1 upgrade
The module path is github.com/hashicorp/hcl/v2, and the README says version 2 cannot be imported by a Go project that does not use Go Modules. Its parser and Go API are incompatible with version 1, with no direct migration path. Both major versions can exist in one module through semantic import versioning, which helps a staged migration but does not perform one.
Release v2.25.0 moved the module's compatibility target from Go 1.24 to Go 1.25. Our October 1 sandbox used a Go 1.24 image and completed its measured commands, while the current go.mod declares Go 1.25. New adopters should follow the module declaration rather than treating our container label as a support promise. Pin HCL and the Go toolchain together in CI.
Deeply nested input needs an outer limit
Issue 809 reports that enough nested parentheses can overflow the Go stack in the recursive-descent parser. The report says this ends the process with a fatal error that recover() cannot catch. That is a specific concern for a service accepting configuration from untrusted users. Limit upload size and nesting before parsing, then run adversarial fixtures against the exact HCL version you ship.
This warning does not cancel the clean result from our 36 tests. It defines where those tests stop. HCL's parser gives product teams a strong base for a human-facing language, but the host remains responsible for resource limits and accepted semantics. A local CLI reading files from its operator faces a different risk than a multi-tenant API parsing anonymous submissions.
The September release and October push show active maintenance
GitHub showed 5,811 stars and 233 combined issues and pull requests on October 2, 2026. A search of the tracker returned 176 open issues, including reports updated in late September. The repository was pushed on October 1. Release v2.25.0 shipped on September 15 with Go 1.25 compatibility, hclwrite additions, parser recovery fixes, and a dependency update.
HCL is the practical choice for a Go product whose configuration needs blocks, labels, expressions, and source-aware diagnostics. The 93-second install and 55 seconds of build plus tests were uneventful in our run. The expensive part comes later: once users write this language, its syntax and behavior become an interface your product must preserve.

