Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Prefix Blocks

Prefix blocks group entries under a common key prefix. They are a syntactic convenience that does not introduce nested objects in the evaluated output.

Syntax

A prefix block consists of:

  1. A key (word key or quoted key) alone on its line — the opener. After comment stripping, nothing but the key may remain on the line.
  2. A body of items (entries, nested prefix blocks, block strings), each indented deeper than the opener’s key.
server.
  host localhost
  port 8080
{
  "server.host": "localhost",
  "server.port": 8080
}

Opener recognition

A key alone on a line is recognized as a block opener when the next item line — skipping blank lines and comment-only lines — is indented deeper than the key:

server.
  # comment lines do not affect recognition
  host localhost

If the next item line is not deeper (same indentation, shallower, or EOF), the key is not an opener and the parse error “missing value for the key” is produced (see Keys):

lonely
next 1

There is no syntax for an empty block: a prefix block always contains at least one item. (A prefix block contributes no output of its own, so an empty block would produce nothing anyway.)

An inline comment after the key does not prevent opener recognition:

server. # the web server
  host localhost

Body Indentation

The first item of the body determines the body indent \( I_{body} \), which must be strictly greater than the opener key’s indentation \( I_{key} \). Every subsequent item of the body must be indented at exactly \( I_{body} \).

The amount of indentation is free (any number of spaces ≥ 1 deeper than the opener) and is chosen independently for each block.

An item line ends the block when its indentation is \( \le I_{key} \). The indentation of such a line must match the body indent of one of the enclosing blocks (or column 0 for the top level); otherwise the parse error “indentation does not match any enclosing block” is produced.

a.
  b.
    c 1
x 2

The line x 2 at column 0 closes both b. and a..

{
  "a.b.c": 1,
  "x": 2
}
a.
    x 1
  y 2

The line y 2 has indentation 2, which matches neither the body indent of a. (4) nor the top level (0) — this is a parse error.

A line indented deeper than \( I_{body} \), where the preceding item is not a block opener (and not a block string header), is also a parse error: “unexpected indentation”.

a 1
  b 2

a 1 is an entry, not an opener, so the indented b 2 is a parse error.

Blank lines and comment-only lines may appear at any indentation and never open or close a block:

server.
  host localhost
# a comment at column 0 does not close the block
  port 8080
{
  "server.host": "localhost",
  "server.port": 8080
}

Prefix Concatenation

During evaluation, the key of the prefix block is prepended to each key inside the block. No separator character (such as .) is automatically inserted. The concatenation is a simple string join.

server
  .host localhost
  .port 8080

The inner keys are .host and .port. Prepending server yields server.host and server.port.

{
  "server.host": "localhost",
  "server.port": 8080
}

Equivalently, the dot can be written on the opener instead:

server.
  host localhost
  port 8080

If neither side provides a separator, the prefix is joined directly:

http_
  port 80
{ "http_port": 80 }

This is equivalent to writing http_port 80 at the top level.

Nesting

Prefix blocks can be nested: an opener inside a block body introduces a deeper body. The prefixes accumulate from the outermost block inward.

outer
  inner
    key value

The key key is inside inner, which is inside outer. The accumulated key is outerinnerkey.

{ "outerinnerkey": "value" }

To get dotted keys, include the dots explicitly:

a.
  b.
    c value
{ "a.b.c": "value" }

Entries and nested blocks can be mixed freely within a body:

server.
  host localhost
  tls.
    cert /etc/ssl/cert.pem
  port 8080
{
  "server.host": "localhost",
  "server.tls.cert": "/etc/ssl/cert.pem",
  "server.port": 8080
}

Blocks With Various Value Types

Entries inside prefix blocks support all value types — Line Strings, Integers, Booleans, Quoted Strings, and Block Strings.

block.
  str hello world
  num 42
  flag true
  neg -1
  quoted "value"
  text |
    multi
    line
{
  "block.str": "hello world",
  "block.num": 42,
  "block.flag": true,
  "block.neg": -1,
  "block.quoted": "value",
  "block.text": "multi\nline\n"
}

For block strings inside a prefix block, the parent indentation \( I_{parent} \) is the indentation of the entry’s key within the body — see Nested Block Strings.