Features
Easy to model data
Structure your configuration with blocks, nested blocks, and tables. Use IDs to name instances and decorators to attach metadata. Tables give you typed, tabular data inline — no separate CSV or YAML files needed.
server #web-1 {
host = "0.0.0.0"
port = 8080
tls {
cert = "/etc/certs/server.crt"
key = "/etc/certs/server.key"
}
}
table "permissions" {
role : string
resource : string
action : string
| "admin" | "users" | "delete" |
| "viewer" | "users" | "read" |
}Dynamic configuration
Use variables, string interpolation, arithmetic, for loops, and conditionals to generate configuration without repetition. Compute values from other values and expand blocks dynamically.
let base_port = 8000
let regions = ["us-east-1", "eu-west-1"]
for region in regions {
deployment deploy-${region} {
region = region
port = base_port
}
}
service "api" {
if env == "prod" {
replicas = 3
} else {
replicas = 1
}
}Secure import system
Split configuration across files with imports and share common definitions via installable libraries. Imports are restricted to local file paths and installed libraries — remote URLs are deliberately unsupported to prevent supply-chain attacks and ensure configs are fully auditable.
// Relative file imports
import "./shared/constants.wcl"
import "./services/auth.wcl"
// Installed library imports
import <myapp.wcl>
service {
timeout = default_timeout
retries = default_retries
}Macro system
Define function macros to stamp out blocks from parameters, or attribute macros to transform blocks in place. Macros reduce boilerplate and enforce patterns across your configuration.
macro service_endpoint(name: string, port: int) {
service name {
port = port
health_path = "/healthz"
}
}
service_endpoint("api", 8080)
service_endpoint("worker", 9090)Schema validation
Define schemas with typed fields, constraints like @min, @max, @pattern, and @one_of, plus cross-references via @ref. Schemas catch type mismatches, missing required fields, and constraint violations at parse time — before your config ever runs.
schema "service" @id_pattern("svc-*") {
port: int @required
@validate(min = 1, max = 65535)
region: string
@validate(one_of = ["us-east-1", "eu-west-1"])
replicas: int @default(1)
@validate(min = 1, max = 100)
}
service "svc-api" {
port = 8080
region = "us-east-1"
replicas = 3
}Use WCL from your favorite language
Rust
Native crate. The core implementation — zero overhead.
cargo add wclPython
WASM-powered Python package. pip install and go.
pip install pywclJavaScript / WASM
Runs in the browser and Node.js via wasm-bindgen.
npm install wcl-wasmGo
Pure Go package powered by WASM via wazero.
go get github.com/wiltaylor/wcl/bindings/go.NET / C#
NuGet package powered by WASM runtime.
dotnet add package WclLangJava / JVM
Runs on JVM languages via Chicory WASM runtime.
implementation 'io.github.wiltaylor:wcl'Ruby
Ruby gem powered by WASM runtime. Ruby 3.1+.
gem install wclZig
Zig package with native FFI bindings.
zig fetch --save git+https://github.com/wiltaylor/wclC / C++
Static library with a C header. Link against libwcl_ffi.
#include "wcl_ffi.h"Editor & tooling support
VS Code
Extension with syntax highlighting, LSP diagnostics, and completions.
Neovim
Works via the built-in LSP client. Point it at the WCL language server and go.
Zed
Extension with syntax highlighting and LSP integration. Coming soon.
Emacs
Major mode with syntax highlighting and LSP support. Coming soon.
Any LSP-compatible editor
Helix, Sublime Text, and anything else that speaks LSP can use the WCL language server.
Powerful CLI
The wcl command line tool lets you validate, query, convert, and modify configuration files without writing code.
Query your config
Find blocks and attributes with selectors and filters. Search by type, ID, attribute values, or regex patterns. Output as text, JSON, CSV, or WCL.
# Find all services on port 8080
wcl query config.wcl 'service | .port == 8080'
# Find blocks by ID
wcl query config.wcl 'service#svc-api'
# Recursive search with regex
wcl query config.wcl \
'..service | .name =~ ".*-api"' \
--format jsonModify in place
Set values, add blocks, and remove attributes while preserving formatting and comments. Great for scripting config changes in CI.
# Set an attribute value
wcl set config.wcl \
service#svc-api.port 9090
# Add a new block
wcl add config.wcl "service svc-new"
# Remove an attribute
wcl remove config.wcl \
service#svc-api.debugValidate and convert
Run the full validation pipeline or export to JSON, YAML, and TOML. Convert from JSON back into WCL.
# Validate with strict mode
wcl validate config.wcl --strict
# Evaluate and export as JSON
wcl eval config.wcl --format json
# Convert between formats
wcl convert config.wcl --to yaml
wcl convert data.json --from jsonFormat and inspect
Auto-format files to a consistent style or inspect the AST, scopes, and dependency graph for debugging.
# Format in place
wcl fmt config.wcl --write
# Check formatting in CI
wcl fmt config.wcl --check
# Inspect the resolved document
wcl inspect config.wcl --hir