Skip to main content

File-driven Config

Load a YAML config file at compile time, validate it against a typed schema, and reshape it into a deployment manifest.

Source

examples/file-driven-config/input.yaml
services:
- name: api
port: 8080
enabled: true
- name: worker
port: 9090
enabled: true
- name: admin
port: 7070
enabled: false

database:
host: db.internal
port: 5432
name: app
examples/file-driven-config/main.rank
/// Reads a YAML config file at compile time and reshapes it into a
/// deployment manifest. Shows File::Read with a typed schema and
/// stdlib transforms on the loaded data.

use std::File
use std::Path
use std::collections::{ filter, map }
use std::Emit

ServiceEntry = Object {
name: string,
port: number,
enabled: bool,
}

InputConfig = Object {
services: [ServiceEntry],
database: Object {
host: string,
port: number,
name: string,
},
}

DeployedService = Object {
name: string,
port: number,
address: string,
}

response = File::Read<InputConfig> {
path: Path::join([`input.yaml`]),
format: `yaml`,
}

input = response.body

active_services: [DeployedService] = input.services
|> filter(|svc: ServiceEntry| svc.enabled)
|> map(|svc: ServiceEntry| -> DeployedService {
return {
name: svc.name,
port: svc.port,
address: `${svc.name}.internal:${svc.port}`,
}
})

manifest = {
services: active_services,
database: input.database,
}

pub main = || Emit::manifest({
entries: [
{
path: Path::join([`manifest.json`]),
format: `json`,
value: manifest,
},
{
path: Path::join([`manifest.yaml`]),
format: `yaml`,
value: manifest,
},
]
})

Output

// manifest.json
{
"services": [
{ "name": "api", "port": 8080, "address": "api.internal:8080" },
{ "name": "worker", "port": 9090, "address": "worker.internal:9090" }
],
"database": {
"host": "db.internal",
"port": 5432,
"name": "app"
}
}

The admin service is excluded because enabled: false. The same manifest is also emitted as manifest.yaml.

Key concepts

  • File::Read<T> — reads and parses a file into the typed schema T. A schema mismatch is a compile-time error.
  • response.body — the parsed, type-checked content of the file.
  • response.ctx — metadata: { path, format }.
  • Path::join — constructs a Path::RelativePath from path segments. Paths are resolved relative to the project source root.
  • Emit::manifest(...) — emits both JSON and YAML artifacts from the same typed manifest descriptor.
  • Filter then map — the pipe chain keeps only enabled services and builds the address field, leaving the database block untouched.

Run it

rank examples/file-driven-config