Alpha

Configuration, Specified.

Type-safe, SMT-validated configuration from a single .dox source. Define it once, validate it at compile time, emit JSON or YAML.

YAML typos crash production. JSON has no types. Dhall has types but no real validation. Pkl locks you in. CUE validates at runtime. Jsonnet gives you string soup. You deserve a configuration language that catches mistakes before they ship — with output in every format you need.

Write once, output everywhere

.dox source
import std

type DatabaseConfig
  host: Text
  port: Port
  name: Text
  maxConnections: Natural
  ssl: Boolean

valid DatabaseConfig
  maxConnections >= 1 && maxConnections <= 1000
    | Connection pool must be 1-1000

production: DatabaseConfig
  host: "db.prod.internal"
  port: Port 5432
  name: "myapp"
  maxConnections: Natural 100
  ssl: true

Generate Config

Unlike other codegen targets, JSON and YAML generation takes a constant name — Paradox evaluates the expression, checks all constraints, and emits the result.

Generate JSON
$ paradox generate --json production

{
  "host": "db.prod.internal",
  "port": 5432,
  "name": "myapp",
  "maxConnections": 100,
  "ssl": true
}
Generate YAML
$ paradox generate --yaml production

host: db.prod.internal
port: 5432
name: myapp
maxConnections: 100
ssl: true
You can also write to a file: paradox generate --json production --out prod.json

Why Paradox for Config?

SMT-Verified Constraints

Validation runs at compile time via Z3. Invalid config never makes it to production.

Error: Validation failed
  port > 0 && port <= 65535
  | Port must be between 1 and 65535
  port = -1

Simple CLI

Generate JSON or YAML for any constant by name. Paradox evaluates the expression and validates constraints before emitting output.

$ paradox generate \
    --json production

$ paradox generate \
    --yaml production

$ paradox generate \
    --json production \
    --out prod.json

Programmable Config

Functions, pattern matching, conditionals. Template environments without copy-paste.

envConfig: env: Text. DatabaseConfig
    host: if env == "prod"
      then "db.prod.internal"
      else "localhost"
    port: 5432
    name: "myapp"
    maxConnections:
      if env == "prod"
        then 100
        else 5
    ssl: env == "prod"

How Paradox Compares

Feature Paradox Dhall Pkl CUE Jsonnet
Type Safety Refinement types (SMT) Total types Schema types Constraints None
Validation Compile-time (Z3) Type-level only Runtime Runtime None
Functions Yes + pattern match Yes (total) Yes Limited Yes
IDE Support LSP LSP LSP + IntelliJ LSP None

Advanced: Unions + Validated Wrappers

Wrap primitive types with validation. Use unions for environment-specific config. Invalid construction is refused at compile time.

import std

wrap DbPort: Integer

valid DbPort
  unwrap > 0 && unwrap <= 65535 | Port must be 1-65535

wrap PoolSize: Integer

valid PoolSize
  unwrap >= 1 && unwrap <= 500 | Pool size must be 1-500

union Environment
  production
  staging
  development

type ServiceConfig
  env: Environment
  dbHost: Text
  dbPort: DbPort
  pool: PoolSize
  debug: Boolean

prodConfig: ServiceConfig
  env: production
  dbHost: "db.prod.internal"
  dbPort: DbPort 5432
  pool: PoolSize 100
  debug: false
Try changing dbPort: DbPort 70000 in prodConfig — Paradox will reject it at compile time with "Port must be 1-65535". No runtime surprises.