Top Related Projects
Go configuration with fangs
YAML support for the Go language.
TOML parser for Golang with reflection.
Go library for the TOML file format
A Go port of Ruby's dotenv library (Loads environment variables from .env files)
Golang library for managing configuration data from environment variables
Quick Overview
HCL (HashiCorp Configuration Language) is a structured configuration language developed by HashiCorp. It is designed to be both human-readable and machine-friendly, making it ideal for use in configuration files and data serialization. HCL is used extensively in HashiCorp products like Terraform and Consul.
Pros
- Easy to read and write, with a syntax similar to JSON but more human-friendly
- Supports comments, making it easier to document configuration files
- Offers advanced features like interpolation, variables, and functions
- Can be used as a general-purpose configuration language outside of HashiCorp products
Cons
- Less widely adopted compared to formats like JSON or YAML
- May require additional parsing libraries in some programming languages
- Learning curve for users unfamiliar with HCL syntax
- Limited built-in data types compared to some other configuration languages
Code Examples
- Basic structure and variable usage:
variable "region" {
default = "us-west-2"
}
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
region = var.region
}
- List and map usage:
variable "availability_zones" {
type = list(string)
default = ["us-west-2a", "us-west-2b", "us-west-2c"]
}
variable "tags" {
type = map(string)
default = {
Environment = "Production"
Project = "MyApp"
}
}
- Conditional expressions:
resource "aws_instance" "example" {
instance_type = var.environment == "production" ? "t2.medium" : "t2.micro"
tags = {
Name = var.name != "" ? var.name : "default-instance"
}
}
Getting Started
To use HCL in your project, you can start by creating a file with a .hcl
extension. Here's a simple example:
# my_config.hcl
app_name = "MyApp"
server {
host = "localhost"
port = 8080
}
database {
url = "postgres://user:password@localhost:5432/mydb"
max_conn = 100
}
To parse this HCL file in Go, you can use the official HCL library:
package main
import (
"fmt"
"github.com/hashicorp/hcl/v2/hclsimple"
)
type Config struct {
AppName string `hcl:"app_name"`
Server Server `hcl:"server,block"`
Database Database `hcl:"database,block"`
}
type Server struct {
Host string `hcl:"host"`
Port int `hcl:"port"`
}
type Database struct {
URL string `hcl:"url"`
MaxConn int `hcl:"max_conn"`
}
func main() {
var config Config
err := hclsimple.DecodeFile("my_config.hcl", nil, &config)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", config)
}
This example demonstrates how to define a configuration structure and parse an HCL file into it using the hclsimple
package.
Competitor Comparisons
Go configuration with fangs
Pros of Viper
- Supports multiple configuration formats (JSON, TOML, YAML, HCL, etc.)
- Provides live watching and automatic reloading of configuration files
- Offers environment variable binding and command-line flag integration
Cons of Viper
- More complex setup and usage compared to HCL's simplicity
- Potential performance overhead due to its extensive feature set
- May be overkill for projects with simple configuration needs
Code Comparison
HCL:
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
}
Viper:
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
err := viper.ReadInConfig()
instanceType := viper.GetString("instance_type")
Summary
HCL is a dedicated configuration language with a focus on simplicity and readability, making it ideal for infrastructure-as-code scenarios. Viper, on the other hand, is a more comprehensive configuration solution for Go applications, offering flexibility and advanced features at the cost of increased complexity. The choice between the two depends on the specific needs of your project and the desired balance between simplicity and feature richness.
YAML support for the Go language.
Pros of yaml
- Widely adopted and supported across multiple programming languages
- Simple and human-readable syntax, especially for complex nested structures
- Extensive documentation and community support
Cons of yaml
- Less expressive than HCL for configuration-specific use cases
- Potential security risks due to arbitrary code execution in some implementations
- Stricter indentation rules can lead to formatting errors
Code Comparison
yaml:
server:
host: localhost
port: 8080
database:
name: mydb
user: admin
HCL:
server {
host = "localhost"
port = 8080
database {
name = "mydb"
user = "admin"
}
}
Key Differences
- Syntax: yaml uses indentation and colons, while HCL uses braces and equals signs
- Typing: yaml has implicit typing, whereas HCL requires explicit type declarations for certain values
- Use case: yaml is a general-purpose data serialization format, while HCL is specifically designed for configuration files
Conclusion
Both yaml and HCL have their strengths and are suitable for different scenarios. yaml excels in general data serialization and cross-language compatibility, while HCL offers a more tailored experience for configuration management, particularly in HashiCorp's ecosystem.
TOML parser for Golang with reflection.
Pros of TOML
- Simpler syntax, easier to read and write for non-programmers
- Widely adopted standard with implementations in many languages
- Better support for complex data structures like arrays of tables
Cons of TOML
- Less flexible for configuration-as-code scenarios
- Limited support for dynamic expressions or interpolation
- May require more verbose syntax for deeply nested structures
Code Comparison
TOML:
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
HCL:
database {
server = "192.168.1.1"
ports = [8001, 8001, 8002]
connection_max = 5000
enabled = true
}
Both HCL and TOML are configuration languages, but they serve different purposes. TOML is designed for simplicity and readability, making it ideal for configuration files that need to be edited by humans. It's widely adopted and has a standardized specification.
HCL, on the other hand, is more powerful and flexible, designed specifically for infrastructure-as-code scenarios. It supports features like dynamic expressions and interpolation, which are crucial for complex configuration management tasks.
While TOML excels in straightforward configuration scenarios, HCL shines in more complex, programmatic environments where configuration and code intersect. The choice between them depends on the specific needs of the project and the target audience for the configuration files.
Go library for the TOML file format
Pros of go-toml
- Simpler syntax and easier to read for basic configurations
- Better support for TOML specification compliance
- Faster parsing and encoding performance for TOML files
Cons of go-toml
- Less flexible for complex configurations
- Limited support for custom data types and structures
- Fewer advanced features compared to HCL's rich functionality
Code Comparison
go-toml:
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
HCL:
database {
server = "192.168.1.1"
ports = [8001, 8001, 8002]
connection_max = 5000
enabled = true
}
Summary
go-toml is ideal for simpler configurations and strict TOML compliance, while HCL offers more flexibility and advanced features for complex configurations. go-toml excels in performance and readability for basic use cases, but HCL provides more powerful tools for sophisticated configuration needs. The choice between the two depends on the specific requirements of the project and the desired balance between simplicity and flexibility.
A Go port of Ruby's dotenv library (Loads environment variables from .env files)
Pros of godotenv
- Simpler and more lightweight, focusing solely on environment variable management
- Easy to use with minimal setup required
- Follows the widely-used .env file format, making it familiar to developers from various backgrounds
Cons of godotenv
- Limited functionality compared to HCL's more comprehensive configuration capabilities
- Less suitable for complex configuration scenarios or hierarchical data structures
- Lacks advanced features like variable interpolation and multi-file support
Code Comparison
godotenv:
import "github.com/joho/godotenv"
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
HCL:
import "github.com/hashicorp/hcl/v2/hclsimple"
type Config struct {
Name string `hcl:"name"`
Version string `hcl:"version"`
}
var config Config
err := hclsimple.DecodeFile("config.hcl", nil, &config)
if err != nil {
log.Fatalf("Failed to load configuration: %s", err)
}
godotenv is ideal for simple environment variable management, while HCL offers a more powerful and flexible configuration solution for complex applications. godotenv is easier to set up and use, but HCL provides advanced features like variable interpolation and structured data representation. Choose godotenv for straightforward environment variable handling, and HCL for more sophisticated configuration needs in larger projects.
Golang library for managing configuration data from environment variables
Pros of envconfig
- Simpler and more lightweight, focusing solely on environment variable configuration
- Easier to use for basic configuration needs, with less setup required
- Directly maps environment variables to struct fields, reducing boilerplate code
Cons of envconfig
- Less flexible for complex configuration scenarios
- Limited to environment variables, lacking support for other configuration sources
- Fewer advanced features compared to HCL (e.g., no interpolation or functions)
Code Comparison
envconfig:
type Config struct {
Host string `envconfig:"HOST"`
Port int `envconfig:"PORT"`
}
var c Config
err := envconfig.Process("myapp", &c)
HCL:
config {
host = "localhost"
port = 8080
}
type Config struct {
Host string `hcl:"host"`
Port int `hcl:"port"`
}
var c Config
err := hcl.Decode(&c, hclBytes)
Summary
envconfig is a simpler solution for environment variable-based configuration, while HCL offers a more comprehensive and flexible configuration language. envconfig is ideal for projects with straightforward configuration needs, whereas HCL is better suited for complex configurations and supports multiple data sources.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
HCL
HCL is a toolkit for creating structured configuration languages that are both human- and machine-friendly, for use with command-line tools. Although intended to be generally useful, it is primarily targeted towards devops tools, servers, etc.
NOTE: This is major version 2 of HCL, whose Go API is incompatible with major version 1. Both versions are available for selection in Go Modules projects. HCL 2 cannot be imported from Go projects that are not using Go Modules. For more information, see our version selection guide.
HCL has both a native syntax, intended to be pleasant to read and write for humans, and a JSON-based variant that is easier for machines to generate and parse.
The HCL native syntax is inspired by libucl, nginx configuration, and others.
It includes an expression syntax that allows basic inline computation and, with support from the calling application, use of variables and functions for more dynamic configuration languages.
HCL provides a set of constructs that can be used by a calling application to construct a configuration language. The application defines which attribute names and nested block types are expected, and HCL parses the configuration file, verifies that it conforms to the expected structure, and returns high-level objects that the application can use for further processing.
package main
import (
"log"
"github.com/hashicorp/hcl/v2/hclsimple"
)
type Config struct {
IOMode string `hcl:"io_mode"`
Service ServiceConfig `hcl:"service,block"`
}
type ServiceConfig struct {
Protocol string `hcl:"protocol,label"`
Type string `hcl:"type,label"`
ListenAddr string `hcl:"listen_addr"`
Processes []ProcessConfig `hcl:"process,block"`
}
type ProcessConfig struct {
Type string `hcl:"type,label"`
Command []string `hcl:"command"`
}
func main() {
var config Config
err := hclsimple.DecodeFile("config.hcl", nil, &config)
if err != nil {
log.Fatalf("Failed to load configuration: %s", err)
}
log.Printf("Configuration is %#v", config)
}
A lower-level API is available for applications that need more control over the parsing, decoding, and evaluation of configuration. For more information, see the package documentation.
Why?
Newcomers to HCL often ask: why not JSON, YAML, etc?
Whereas JSON and YAML are formats for serializing data structures, HCL is a syntax and API specifically designed for building structured configuration formats.
HCL attempts to strike a compromise between generic serialization formats such as JSON and configuration formats built around full programming languages such as Ruby. HCL syntax is designed to be easily read and written by humans, and allows declarative logic to permit its use in more complex applications.
HCL is intended as a base syntax for configuration formats built around key-value pairs and hierarchical blocks whose structure is well-defined by the calling application, and this definition of the configuration structure allows for better error messages and more convenient definition within the calling application.
It can't be denied that JSON is very convenient as a lingua franca for interoperability between different pieces of software. Because of this, HCL defines a common configuration model that can be parsed from either its native syntax or from a well-defined equivalent JSON structure. This allows configuration to be provided as a mixture of human-authored configuration files in the native syntax and machine-generated files in JSON.
Information Model and Syntax
HCL is built around two primary concepts: attributes and blocks. In native syntax, a configuration file for a hypothetical application might look something like this:
io_mode = "async"
service "http" "web_proxy" {
listen_addr = "127.0.0.1:8080"
process "main" {
command = ["/usr/local/bin/awesome-app", "server"]
}
process "mgmt" {
command = ["/usr/local/bin/awesome-app", "mgmt"]
}
}
The JSON equivalent of this configuration is the following:
{
"io_mode": "async",
"service": {
"http": {
"web_proxy": {
"listen_addr": "127.0.0.1:8080",
"process": {
"main": {
"command": ["/usr/local/bin/awesome-app", "server"]
},
"mgmt": {
"command": ["/usr/local/bin/awesome-app", "mgmt"]
},
}
}
}
}
}
Regardless of which syntax is used, the API within the calling application is the same. It can either work directly with the low-level attributes and blocks, for more advanced use-cases, or it can use one of the decoder packages to declaratively extract into either Go structs or dynamic value structures.
Attribute values can be expressions as well as just literal values:
# Arithmetic with literals and application-provided variables
sum = 1 + addend
# String interpolation and templates
message = "Hello, ${name}!"
# Application-provided functions
shouty_message = upper(message)
Although JSON syntax doesn't permit direct use of expressions, the interpolation syntax allows use of arbitrary expressions within JSON strings:
{
"sum": "${1 + addend}",
"message": "Hello, ${name}!",
"shouty_message": "${upper(message)}"
}
For more information, see the detailed specifications:
Changes in 2.0
Version 2.0 of HCL combines the features of HCL 1.0 with those of the interpolation language HIL to produce a single configuration language that supports arbitrary expressions.
This new version has a completely new parser and Go API, with no direct migration path. Although the syntax is similar, the implementation takes some very different approaches to improve on some "rough edges" that existed with the original implementation and to allow for more robust error handling.
It's possible to import both HCL 1 and HCL 2 into the same program using Go's semantic import versioning mechanism:
import (
hcl1 "github.com/hashicorp/hcl"
hcl2 "github.com/hashicorp/hcl/v2"
)
Acknowledgements
HCL was heavily inspired by libucl, by Vsevolod Stakhov.
HCL and HIL originate in HashiCorp Terraform, with the original parsers for each written by Mitchell Hashimoto.
The original HCL parser was ported to pure Go (from yacc) by Fatih Arslan. The structure-related portions of the new native syntax parser build on that work.
The original HIL parser was ported to pure Go (from yacc) by Martin Atkins. The expression-related portions of the new native syntax parser build on that work.
HCL 2, which merged the original HCL and HIL languages into this single new language, builds on design and prototyping work by Martin Atkins in zcl.
Top Related Projects
Go configuration with fangs
YAML support for the Go language.
TOML parser for Golang with reflection.
Go library for the TOML file format
A Go port of Ruby's dotenv library (Loads environment variables from .env files)
Golang library for managing configuration data from environment variables
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot