hocon

The HOCON format

HOCON is a superset of JSON: every JSON document is valid HOCON, but HOCON adds comments, optional quoting, optional commas, and a handful of conveniences that make hand-written config pleasant.…

HOCON is a superset of JSON: every JSON document is valid HOCON, but HOCON adds comments, optional quoting, optional commas, and a handful of conveniences that make hand-written config pleasant. This page covers the syntax hocon parses today.

Objects and fields

The top-level braces are optional, and a field is a key, a separator (= or :), and a value:

name = "Roamer"
version : "1.0"

= and : are interchangeable. Fields are separated by a newline or a comma; a trailing comma is allowed:

a = 1, b = 2
c = 3
xs = [1, 2, 3,]

When a value is an object, the separator may be omitted entirely:

window {
  width  = 1024
  height = 768
}

Comments

Both # and // start a comment that runs to the end of the line:

# a full-line comment
port = 8080   // a trailing comment

Values

hocon recognizes the JSON value types plus unquoted strings:

string  = "quoted text"
bare    = an-unquoted-string
number  = 8080
float   = 1.5
flag    = true
empty   = null
list    = [1, "two", true]
nested  = { a = 1, b = 2 }

true, false, and null are keywords; anything matching a number literal is a number; everything else is a string.

Quoting

Note

HOCON allows unquoted strings, but forbids these characters inside them: $ " { } [ ] : = , + # ^ ? ! @ * & `. Most natural-language strings hit one of them, so quote your message strings. hocon raises a parse error pointing at the offending character rather than guessing — this is spec-correct behavior.

Bare words are convenient for identifiers, numeric values, and simple paths (localhost, recent-files, 8080). For anything with punctuation, quote it.

String escapes

Quoted strings support the JSON escapes — \", \\, \/, \n, \t, \r, \b, \f, and \uXXXX:

path    = "C:\\Users\\Ada"
caption = "line one\nline two"
heart   = "❤"

Triple-quoted strings are raw — no escapes are processed and newlines are kept verbatim, which is handy for embedded text:

banner = """
  Welcome to Roamer.
  Press ? for help.
"""

Path-expression keys

A key may be a dotted path, which expands into nested objects. These two documents are equivalent:

a.b.c = value
a { b { c = value } }

Keys that target the same object merge, so you can group related settings flatly:

cart.items   = "{count} items"
cart.empty   = "Your cart is empty"

resolves to a cart object with both items and empty.

Arrays

Array elements are separated by commas or newlines, with an optional trailing comma, and may be any value type — including objects and nested arrays:

ports = [
  8080
  8081
  8082,
]

users = [
  { name = "Ada",  admin = true  },
  { name = "Alan", admin = false },
]

Substitutions

${path} references another value, and ${?path} is its optional form. They resolve against the merged document, so they are order-independent:

host = localhost
url  = ${host}        # → "localhost"

See the substitutions guide for the full rules — environment fallback, object copying, and cycle detection.

Value concatenation

Several pieces written on one line with only whitespace between them concatenate into a single value. Strings, numbers, booleans, and substitutions join into one string, with the interior whitespace preserved and the ends trimmed:

host = example.com
port = 8080
url  = "http://"${host}":"${port}   # → "http://example.com:8080"
full = first   middle  last         # → "first   middle  last"

Arrays concatenate element-wise, and objects deep-merge left to right:

xs   = [1, 2] [3, 4]                 # → [1, 2, 3, 4]
conf = ${defaults} { retries = 5 }   # the defaults object with retries overridden

Mixing kinds that cannot combine — an object or array joined with a string — raises a HoconConcatException.

Durations and sizes

A value can be read as a time duration or a memory size with the dedicated getters; in the source it is just a number with a unit suffix (an optional space is allowed):

timeout   = 10s
poll      = 500ms
linger    = 5 minutes
cache     = 512K
max-upload = 10MB

getDuration returns a cross-platform FiniteDuration; getBytes returns a Long. Duration units are ns, us, ms, s, m, h, d (and their long spellings), with a bare number read as milliseconds. Size units distinguish powers of 1024 (K, Ki, KiB, …) from powers of 1000 (kB, MB, …), with a bare number read as bytes. See the Config reference.

Not yet supported

include directives — pulling in other files — are on the roadmap.

Because unquoted strings forbid : and // starts a comment, URLs must be quoted (url = "https://example.com") — this matches the reference implementation.

Search

Esc
to navigate to open Esc to close