A configuration language for application-level configs
CLEO is specifically intended for configuration files that power your applications, focusing on clarity, nested structures, and environment-based values to keep your app setup flexible. This page highlights some key points, including examples, data types, command-line usage, integration with Go, and Q&As.
CLEO uses an indentation-based structure (multiples of 4 spaces) and # for comments.
Lists start with *
, environment variables are written as $VARIABLE_NAME
,
and references point to other keys or blocks via slash-based paths (e.g. /Server/Port
).
References must appear after the block or key they reference. Special keys can be any symbols up to the
next space, but an empty key (i.e. ""
) is not allowed.
#
*
$DB_HOST
, etc.)/Database/Port
) that come after the definition they referenceHere are some examples of basic usage.
Nested values can be defined in indented blocks:
# Set the environment.
Environment "production"
# Define logging.
Logging
Level "debug"
# A server block.
Server
Host "localhost"
Port 8080
Lists are indented under their key. For example, multiple output destinations under Logging
:
Logging
# Each '*' line is one list item.
Outputs
* "stdout"
* "file"
Use references for reusing data from earlier definitions:
Server
Host "localhost"
Port 8080
# MainServer references Server, so it appears after.
MainServer /Server
CLEO covers these core types: strings (inline/multiline), booleans, integers, floats, lists, blocks, environment variables, and references. Below are valid values, with examples.
Inline strings (e.g. "Hello"
) or multiline strings indented under a key:
# Inline string:
App
Name "MyApp"
# Multiline string:
Description
"This is a multi-line
"description.
Strings can contain any characters except the closing quote. For multiline strings, each new line is another chunk of text appended with a newline in the final value.
FeatureFlags
Enabled true
Experimental false
Valid values: true
or false
(unquoted).
Server
Port 8080
NegativePort -123
ZeroPort 0
Valid integer values can be negative, zero, or positive.
Limits
Ratio 0.75
NegativeFloat -3.14
ZeroFloat 0.0
Valid float values require a decimal point (e.g. 3.14
, -2.0
).
Servers
* "api-server"
* "worker-server"
* "db-server"
Each *
line indicates one list item. All items can be any valid data type (strings, references, blocks, etc.).
App
Name "MyApp"
Server
Host "localhost"
Port 8080
Blocks nest further keys or lists by indenting under the block’s name.
Database
Host $DB_HOST
Password $DB_PASS
$SOMEVAR
is replaced at parse time with the environment variable’s value.
A path of slash-separated tokens referencing previously declared blocks or keys:
App
Title "Hello"
Paths
# WebRoot references Title from App.
WebRoot /App/Title
The file must define App
(and Title
) before Paths
.
Parse CLEO files and output JSON for tooling or inspection.
go install code.nicktrevino.com/cleo/cmd/cleo@latest
Then run cleo
in your terminal.
cleo -config config.cleo
If config.cleo
has:
Name "MyApp"
Database
Host $DB_HOST
Port 5432
The output JSON might look like:
{
"Name": "MyApp",
"Database": {
"Host": "localhost",
"Port": 5432
}
}
Pipe this output to files or other tools as needed.
Use CLEO’s official library to load configs directly into Go structures.
Given config.cleo
:
App
Name "MyApplication"
Server
Host $HOST_ENV
Port 8080
In your Go code:
package main
import (
"fmt"
"log"
"code.nicktrevino.com/cleo"
)
type Config struct {
App struct {
Name string
Server struct {
Host string
Port int
}
}
}
func main() {
configMap, err := cleo.ParseConfig("./config.cleo")
if err != nil {
log.Fatalf("Failed to parse CLEO: %v", err)
}
fmt.Println("Parsed Map:", configMap)
var c Config
if err := cleo.UnmarshalConfig("./config.cleo", &c); err != nil {
log.Fatalf("Failed to unmarshal: %v", err)
}
fmt.Printf("Go Struct: %+v\n", c)
}
Here, HOST_ENV
is substituted at runtime, and the entire config loads into Config
.
Check out these scenarios showing special keys and advanced references.
Unusual keys remain valid, but cannot be empty:
MyConfig
# Bracket key
[]key "bracket key"
# Numeric key
123key "numeric key"
Combining references with lists of blocks and environment variables:
App
Databases
*
Host $PRIMARY_DB_HOST
Port 5432
*
Host $SECONDARY_DB_HOST
Port 5432
# Reference to the first item in Databases
MainDB /App/Databases/0
CLEO is less ambiguous than YAML, supports references that TOML doesn’t, and leverages environment expansions lacking in JSON. Below are short side-by-side samples illustrating how each format handles nesting and placeholders.
Name "MyApp"
Database
Host $DB_HOST
Credentials
Username $DB_USER
Password $DB_PASS
Name: "MyApp"
Database:
Host: "${DB_HOST}"
Credentials:
Username: "${DB_USER}"
Password: "${DB_PASS}"
Name = "MyApp"
[Database]
Host = "${DB_HOST}"
[Database.Credentials]
Username = "${DB_USER}"
Password = "${DB_PASS}"
{
"Name": "MyApp",
"Database": {
"Host": "${DB_HOST}",
"Credentials": {
"Username": "${DB_USER}",
"Password": "${DB_PASS}"
}
}
}
Absolutely. You’d define keys and blocks for your config, then parse it into JSON (or other structures) if your tooling requires.
CLEO is an acronym for: Concise, Lean, Ergonomic Options