HCL is the HashiCorp configuration language.

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.

Owner
HashiCorp
Consistent workflows to provision, secure, connect, and run any infrastructure for any application.
HashiCorp
Comments
  • add PoC cmd converting HCL to JSON

    add PoC cmd converting HCL to JSON

    This adds an hcl2json command which reads HCL from STDIN and writes indented JSON to STDOUT.

    At the moment it is not friendly at all, and probably is only useful for people who are testing HCL code changes. Before merging, it should be a friendly tool to allow people who :heart: HCL to use it in environments where importing this package is unwieldy.

    Some things it should probably do:

    • [x] hcl2json, hcl2json -h should print usage
    • [x] hcl2json foo.hcl should read from foo.hcl
    • [x] hcl2json - should read from STDIN
    • [x] refactor to extract a CLI struct for testing
    • [x] add tests for the above functionality
    • build through gox?

    Fixes https://github.com/hashicorp/hcl/issues/32

  • HCL2 <-> JSON Transformer?

    HCL2 <-> JSON Transformer?

    Hi all!

    I was wondering if there was anything in the works for a library that could convert HCL2 to JSON and back again, similar to https://github.com/kvz/json2hcl

    Thanks!

  • Fails to parse time.Duration

    Fails to parse time.Duration

    HCL Template

    App {
        PostponeExit = 5s
    }
    

    Expected behavior

    It should be able to parse Go-style time duration.

    Actual behavior

    With a struct like:

    type Conf struct {
    	App struct {
    		PostponeExit time.Duration
    	}
    
    	// ...
    }
    

    We have to use a value 5000000000 to get a 5s duration. If we use 5s as value in hcl file, we get:

    At 3:9: nested object expected: LBRACE got: ASSIGN
    

    And if we use a string like "5s", we get:

    strconv.ParseInt: parsing "5s": invalid syntax
    

    I saw issues related to this. But they were about implementing an unmarshaller interface (which I failed to figure what it is) and not unmarshalling standard duration.

  • `raise()` function for custom error handling (HCL2)

    `raise()` function for custom error handling (HCL2)

    UPDATE (2): Terraform have opened a 'discuss' topic for this capability: https://discuss.hashicorp.com/t/terraform-core-research-ability-to-raise-an-error/35818

    UPDATE: CI Tests are now passing, PR is ready for review and feedback.

    This is my first contribution to Terraform and HCL. Comments, suggestions, and guidance are all welcome.

    Essentially, this update adds a new raise function which Terraform developers can leverage to improve error handling and messaging to users.

    Usage:

    locals {
      progress = 50
      of_total_a = 0
      of_total_b = null
      of_total_c = 100
    }
    locals {
      #raises a custom error using if/then/else syntax:
      my_value = local.of_total_a = null ? raise("invalid denominator") : local.progress / local.of_total_a
    
      #raises a custom error using try():
      my_value = try(local.progress / local.of_total_a, raise("invalid denominator"))
    
      #raises a custom error using coalesce() if value is null:
      my_value = local.progress / coalesce(local.of_total_b, raise("denominator is null"))
    
      # succeeds (no error)
      my_value = try(local.progress / local.of_total_c, raise("(will not be reached)"))
    }
    

    NOTE: This change also requires a change to the Terraform repo, tracked here: https://github.com/hashicorp/terraform/pull/25088

    Resolves https://github.com/hashicorp/terraform/issues/24269

  • cannot find package

    cannot find package "github.com/hashicorp/hcl/v2"

    I am trying to write a provide following the tutorial on link.[https://www.terraform.io/docs/extend/writing-custom-providers.html]

    When I try to do go get github.com/hashicorp/terraform-plugin-sdk/plugin I have the below error:

    package github.com/hashicorp/hcl/v2: cannot find package "github.com/hashicorp/hcl/v2" in any of:
    	/usr/local/go/src/github.com/hashicorp/hcl/v2 (from $GOROOT)
    	/Users/federicoolivieri/go/src/github.com/hashicorp/hcl/v2 (from $GOPATH)
    package github.com/hashicorp/hcl/v2/hclsyntax: cannot find package "github.com/hashicorp/hcl/v2/hclsyntax" in any of:
    	/usr/local/go/src/github.com/hashicorp/hcl/v2/hclsyntax (from $GOROOT)
    	/Users/federicoolivieri/go/src/github.com/hashicorp/hcl/v2/hclsyntax (from $GOPATH)
    

    I then tried go get github.com/hashicorp/hcl/v2but I have pretty much the same error.

  • Add support for indented HEREDOC terminators

    Add support for indented HEREDOC terminators

    This PR adds support for the style of HEREDOC often used in Ruby which allows the terminating marker to be indented if the HEREDOC is started with the sequence "<<-" rather than the usual "<<". This allows users to express documents with more natural indentation:

    resource "template_file" "test" {
        template = <<-HEREDOC
            First Line
            Second Line
        HEREDOC
    }
    

    Note that this does not attempt to add any semantics around removing hanging indent from the actual text of the document, so extra indentation would still be present. We could make use of the canonical style for HCL herre to remove the hanging indent in the style of Ruby which would probably be more predictable for users.

    Fixes https://github.com/hashicorp/hcl/issues/9

    cc @phinze, @mitchellh

  • Multi-line string

    Multi-line string

    I have a rather long command as a string in hcl.

    provisioner "local-exec" {
      command = "knife solo bootstrap -N ${self.name} -j '{\"mysql\": {\"server_root_password\": \"${var.mysql_root_password}\"}}' --no-berkshelf --no-host-key-verify -i ${var.pvt_key} -r ${var.run_list.db} ${var.remote_user}@${self.ipv4_address} | tee -a ${self.name}.log
    }
    

    Is there a way to break it and still keep it decoded as a single string? I can't find anything in test fixtures regarding this.

  • CLI to convert JSON to/from HCL

    CLI to convert JSON to/from HCL

    There seems to be support for JSON <--> HCL; a CLI that makes it easy to convert JSON into HCL would make it easy to integrate HCL into other tool chains?

  • No write support for HCL?

    No write support for HCL?

    It feels like a strange omission not to include write-support for HCL. This decision was probably made with very good reasons but I have yet to discover them.

    Making HCL read-only makes it an all-or-nothing thing: either a human writes the entire configuration file in HCL or the server writes it entirely in JSON (which renders it uneditable, or at least very clumsy, for a human).

    The typical scenario I have in mind is a server that has a big configuration file with lots of bells and whistles. Some of these options are editable in the UI, while others are considered advanced and aren't exposed in the UI (because only 1% of the users would need them).

    I don't see a way to make some variables machine-editable while maintaining an easy configuration language (for humans) for the more advanced options. One example of a configuration format that does support writing (and is reasonably readable) is the git configuration format.

    Advice and recommendations are highly welcome. Let me know if none of this makes any sense, I'll happily clarify.

    Perhaps what I'm doing just isn't part of the scope of HCL. I'd be cool with that too, I'll look for an alternative.

  • Feature request:  better multi-line string formatting

    Feature request: better multi-line string formatting

    Coming from a terraform perspective, I have noticed that code readability deteriorates when column lengths get really long. This problem tends to crop-up frequently with argument string values inside resources, and unfortunately the current syntax options (HEREDOC or newlines inside interpolation functions) are limiting. I'm still learning the internals of HCL, but I think one / both of the following options might work for this:

    1. Multi-line string literal with white-space trimming. Similar to the Python triple-quote ("""):
    tags {
      Name = """${var.foo}-${var.bar}-
                my-application-elb-${var.baz}"""
    }
    
    1. String concatenation operators (and a new-line escape like bash?), similar to (how I do it) in Python:
    tags {
      Name = "${var.foo}-${var.bar}-" + \
             "my-application-elb-${var.baz}"
    }
    

    See previous issue under terraform for background: https://github.com/hashicorp/terraform/issues/8210

    Thoughts?

  • Colon assign

    Colon assign

    implements colon assignment. Doesn't implement deep assignment yet, so hcl/test-fixtures/assign_colon.hcl still fails.

    I implemented this primarily in the parser because I prefer stupid lexers. It would be quite easy to just have a ":" be token EQUAL, so it might be better to implement it that way.

  • Reconcile v1.0.1-vault divergent history

    Reconcile v1.0.1-vault divergent history

    Relates to #486

    The history of the v1.0.1-vault-* releases is somewhat muddled, with divergent history.

    This PR makes no tree changes to the 1.0.x-vault branch, but attaches the history for the releases which are currently not part of the branch, and documents the state of affairs.

    The current tagged releases are:

    • v1.0.1-vault (not actually a tag; instead this is a branch which is used in a tag-like manner, even being present in older Vault go.mod files): A backport of #275 for Vault.
    • v1.0.1-vault-2: A backport of unused key tracking for Vault, but it reverts part of the #275 backport in a commit just titled "wip"
    • v1.0.1-vault-3: Includes all changes in v1.0.1-vault-2, but is not a descendant of the tagged v1.0.1-vault-2 commit, nor on the current 1.0.x-vault branch
    • v1.0.1-vault-4:
      • Squash-merges the changes from v1.0.1-vault-3 into the 1.0.x-vault branch
      • Re-introduces the part of #275 lost in v1.0.1-vault-2 (e80118accb521e47bc5b93104bf46c67d89d2242)
      • "VAULT-8519 - Don't erroneously report nested JSON as unused keys (#559)"
    • v1.0.1-vault-5: By being tagged on the source branch of #559, this tag effectively re-reverts the re-introduction of the part of #275 that was present in v1.0.1-vault, absent in -vault-2 and -vault-3, then back again in vault-4.

    After this PR is merged, there is a needed follow-up action: decide in which direction the reverting and unreverting of part of #275 should actually stay in.

    If it is supposed to be gone, actually revert e80118accb521e47bc5b93104bf46c67d89d2242 on branch 1.0.x-vault so that it doesn't get re-introduced if another version is made.

    If it is supposed to be kept, then make a new release, v1.0.1-vault-6 that includes it again.


    Finally, for clarity, it would be nice to delete the branch used in a tag-like manner, v1.0.1-vault, and replace it with real tag of the same name, pointing at the same commit (cf4c4bf2466d28b8fd0e9953ee5eb7caa3af5418)

  • github: Pin external GitHub Actions to hashes

    github: Pin external GitHub Actions to hashes

    The intention here is to reduce the security risk posed by the supply chain - i.e. externally maintained GitHub Actions.


    Note that I also bumped the major versions of both Actions, which should not make a visible difference. I believe the main reason for the major bump was NodeJS version, where the old version either already is or soon will be EOL anyway, so this is somewhat necessary and optimistic step.

  • Question - Is ordering deterministic

    Question - Is ordering deterministic

    Could you clarify whether hcl ordering is deterministic ? As we know, go maps are not deterministic in their output (i.e. you will get a different order each time).

    Therefore, taking the README example:

      process "main" {
        command = ["/usr/local/bin/awesome-app", "server"]
      }
    
      process "mgmt" {
        command = ["/usr/local/bin/awesome-app", "mgmt"]
      }
    

    And the readme definition:

    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"`
    }
    

    Will the output ALWAYS be as defined in the hcl config file ? i.e. main then mgmt in this example.

    The reason I am asking is because I am writing a playbook type Go app where the tasks need to be undertaken in a specific order otherwise Bad Things Happen (TM). I am looking around for config tooling and hcl looks like it might tick many boxes as long as its output is deterministic.

  • I cannot understand spec.md

    I cannot understand spec.md

    https://github.com/hashicorp/hcl/blob/main/hclsyntax/spec.md

    This file don't tell about backtick-strings, and about 'var', 'type', 'func' keywords, but the main Git readme https://github.com/hashicorp/hcl#readme gives the example with these things!

    type ProcessConfig struct {
    	Type    string   `hcl:"type,label"`
    	Command []string `hcl:"command"`
    }
    
    func main() {
    	var config Config
    ....
    

    so spec.md is not OK?

  • Implement gohcl.EvalContext

    Implement gohcl.EvalContext

    Implement gohcl.EvalContext function, which should be implemented as doc as well.

    1. Simple implementation from struct to EvalContext.Variables .
    2. Cause of Functions are hardcoded, it might could convert .
    3. Ignore empty object to cty.Value ( cty.ListVal or cty.MapVal with empty var might casue error)

    More discuss on #565

Graph-based Declarative Configuration Language
Graph-based Declarative Configuration Language

Virgo Configuration Language Most configuration problems reduce to graphs, e.g. Dockerfiles and Makefiles But there are no graph-based configuration l

Nov 26, 2022
✨Clean and minimalistic environment configuration reader for Golang

Clean Env Minimalistic configuration reader Overview This is a simple configuration reading tool. It just does the following: reads and parses configu

Jan 8, 2023
12 factor configuration as a typesafe struct in as little as two function calls

Config Manage your application config as a typesafe struct in as little as two function calls. type MyConfig struct { DatabaseUrl string `config:"DAT

Dec 13, 2022
JSON or YAML configuration wrapper with convenient access methods.

Config Package config provides convenient access methods to configuration stored as JSON or YAML. This is a fork of the original version. This version

Dec 16, 2022
Configure is a Go package that gives you easy configuration of your project through redundancy

Configure Configure is a Go package that gives you easy configuration of your project through redundancy. It has an API inspired by negroni and the fl

Sep 26, 2022
An opinionated configuration loading framework for Containerized and Cloud-Native applications.
An opinionated configuration loading framework for Containerized and Cloud-Native applications.

Opinionated configuration loading framework for Containerized and 12-Factor compliant applications. Read configurations from Environment Variables, an

Dec 16, 2022
Load configuration in cascade from multiple backends into a struct
Load configuration in cascade from multiple backends into a struct

Confita is a library that loads configuration from multiple backends and stores it in a struct. Supported backends Environment variables JSON files Ya

Jan 1, 2023
Small library to read your configuration from environment variables

envconfig envconfig is a library which allows you to parse your configuration from environment variables and fill an arbitrary struct. See the example

Nov 3, 2022
A minimalist Go configuration library
A minimalist Go configuration library

fig fig is a tiny library for loading an application's config file and its environment into a Go struct. Individual fields can have default values def

Dec 23, 2022
go-up! A simple configuration library with recursive placeholders resolution and no magic.

go-up! A simple configuration library with placeholders resolution and no magic. go-up provides a simple way to configure an application from multiple

Nov 23, 2022
goconfig uses a struct as input and populates the fields of this struct with parameters from command line, environment variables and configuration file.

goconfig goconfig uses a struct as input and populates the fields of this struct with parameters from command line, environment variables and configur

Dec 15, 2022
Go configuration made easy!

gofigure Go configuration made easy! Just define a struct and call Gofigure Supports strings, ints/uints/floats, slices and nested structs Supports en

Sep 26, 2022
Harvest configuration, watch and notify subscriber

Harvester Harvester is a configuration library which helps setting up and monitoring configuration values in order to dynamically reconfigure your app

Dec 26, 2022
go implementation of lightbend's HOCON configuration library https://github.com/lightbend/config

HOCON (Human-Optimized Config Object Notation) Configuration library for working with the Lightbend's HOCON format. HOCON is a human-friendly JSON sup

Dec 3, 2022
🛠 A configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP
🛠 A configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP

config A small configuration library for Go that parses environment variables, JSON files, and reloads automatically on SIGHUP. Example func main() {

Dec 11, 2022
Golang library for managing configuration data from environment variables

envconfig import "github.com/kelseyhightower/envconfig" Documentation See godoc Usage Set some environment variables: export MYAPP_DEBUG=false export

Dec 26, 2022
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.
Light weight, extensible configuration management library for Go. Built in support for JSON, TOML, YAML, env, command line, file, S3 etc. Alternative to viper.

koanf (pronounced conf; a play on the Japanese Koan) is a library for reading configuration from different sources in different formats in Go applicat

Jan 8, 2023
A golang package for parsing ini-style configuration files

Mini Mini is a simple ini configuration file parser. The ini syntax supported includes: The standard name=value Comments on new lines starting with #

Jan 7, 2023
A dead simple configuration manager for Go applications

Store Store is a dead simple configuration manager for Go applications. I didn't like existing configuration management solutions like globalconf, tac

Dec 24, 2022