joetjen.net
EN DE
Configuration language

The CASC configuration format

CASC is a configuration language with a real specification: nested blocks, typed values from durations to IP ranges, variables, environment reads, references to other keys, imports and loops — in a syntax that stays readable as plain text.

Format 1.0

A first look

A CASC file is a list of statements that together build one tree of named values. This one reads an environment file, a few environment variables and a shared variable, and refers from one key to two others:

config.casc
#@version = 1.0

import "env/${APP_ENV:dev}.casc"

@region = ${REGION:"eu-west"}

server {
  host = "0.0.0.0"
  port = !int(${PORT:8080})
}

database {
  host = "db.@{region}.internal"
  *password = ${DB_PASSWORD:?"DB_PASSWORD is required"}
  timeout = 500ms
  cache = 512MiB
}

health.url = "http://%{server.host}:%{server.port}/health"
  • #@version = 1.0 — every file starts with its format version.
  • import pulls in another file; its path may read the environment.
  • @region is a variable, ${…} reads the environment, %{…} refers to another key of the finished tree.
  • 500ms and 512MiB are values of their own types, not strings to parse later.
  • *password is marked secret: the value stays redacted wherever it ends up.
  • :?"…" makes a missing environment variable a load error with your own message.

Design

  • One kind of map. A block and a dotted path are two spellings of the same tree, and blocks written twice merge.
  • Typed literals. Durations, byte sizes, dates and times, IP addresses and tuples are values in the language.
  • Three references, one grammar. @{} variables, ${} environment and %{} config paths share the same defaults, guards, indexes and filters.
  • Explicit merging. Later writes win and blocks deep-merge; the sigils ~, + and - replace, append and remove when that is what you mean.
  • Nothing unknown passes silently. A tag, resolver or import scheme nobody registered is a load error that names it.
  • Secrets in the syntax. A * on a key marks its value secret, and interpolating it keeps the result redacted.

The name is a pun: a cooper makes barrels, and a casc is a cask. The format is what the barrel holds.

File facts

PropertyValue
Extension.casc
EncodingUTF-8
First line#@version = 1.0 — mandatory, in every file
Comments# followed by a space, to the end of the line
ResultOne tree: blocks are maps, leaves are typed values
GrammarPEG, written in Aether — see Grammar

Implementations and tools

These pages describe the format. Each of the following has its own documentation for how it loads or exposes it.

NameLanguageRole
cooperElixirThe reference implementation
cooper_configElixirUses a CASC file as the configuration of a Mix project or release
CASC for VS CodeTypeScriptHighlighting, snippets and a language server
cooperPraxisA port of Cooper, generated from the same grammar
cooper_prxPraxisReads a Praxis project’s config.casc
ichorElixirThe grammar compiler both parsers are generated with

On these pages

  • File structure — header, comments, keys, blocks, merging.
  • Values — every literal type.
  • References — variables, environment, config paths, filters, tags.
  • Imports and loops — splitting and generating configuration, with a complete example.
  • Grammar — the formal grammar and where the reference implementation still differs from it.