Reference Syntax
walkerOS flow configs (flow.json) support dynamic references inside string values. They let you pull in variables, environment values, contract fragments, store instances, secrets, and inline JavaScript without duplicating configuration.
The one rule
walkerOS uses two separator characters, each with a clear meaning:
| Separator | Meaning |
|---|---|
. | A key or path. The resolver looks up what follows in a map or walks it as a dotted path. |
: | A literal value or raw-code payload. The resolver uses what follows verbatim, it is not a name. |
Every reference follows that rule. There are no exceptions.
All references
$var.name look up variables[name] (whole-string returns native type)
$var.name.deep.path walk a dotted path inside the variable
$env.NAME read process.env[NAME]
$env.NAME:default read process.env[NAME] with a literal fallback
$contract.name inject a whole named contract entry
$contract.name.events walk the contract path
$store.id inject a store instance (resolved at bundle time)
$secret.NAME inject a secret value (resolved at deploy time)
$code:(event) => ... inline JavaScript (resolved at bundle time)
$var. — variables
Look up a value in the variables map at config, flow, or step level. Step
overrides flow overrides config.
Variables hold any JSON value, scalars (string, number, boolean), objects, arrays, or whole mapping templates. The reference may include a deep path that walks the value.
{
"variables": {
"measurementId": "G-XXXXXX",
"ga4Items": {
"loop": ["nested", { "map": { "item_id": "data.id" } }]
},
"api": { "version": "v2", "url": "https://api.example.com" }
},
"flows": {
"web": {
"destinations": {
"gtag": {
"config": {
"settings": {
"ga4": { "measurementId": "$var.measurementId" }
},
"mapping": {
"order": {
"complete": {
"data": { "map": { "items": "$var.ga4Items" } }
}
}
}
}
},
"api": {
"config": {
"settings": {
"endpoint": "$var.api.url",
"version": "$var.api.version"
}
}
}
}
}
}
}
Resolution rules:
- A whole-string reference (
"$var.api.url") replaces the value with the variable's native type. Object, array, number, and boolean values are preserved. - An inline reference (
"Bearer $var.token") substitutes a scalar mid-string. Object or array values throw, scalars only. - Variables may reference other variables. Resolution is recursive with cycle detection.
Naming convention: when variables hold structures (mapping templates,
matchers, consent objects), pick a name that signals the shape, for example
ga4ItemMapping, ga4ItemsLoop, consentMarketing, getMastertagJs. Keep
the convention consistent within a single config; we don't enforce a global
prefix or suffix rule.
$env. — environment variables
Read from process.env at runtime. Optionally provide a literal fallback with
the :default suffix.
{
"variables": {
"apiUrl": "$env.API_URL:http://localhost:8080/collect",
"pixelId": "$env.META_PIXEL_ID"
}
}
The : here is the default-value separator, not a name delimiter. The
token after : is used verbatim.
$contract. — contract references
Inject a fragment of a named contract entry. Same whole-string and deep-path
rules as $var.. The contract is fully resolved (extend + wildcards) before
path access, so the value you get is the merged shape.
See Contract for the full structure.
{
"contract": {
"default": {
"schema": {
"properties": {
"globals": { "required": ["country"] }
}
},
"events": {
"product": {
"add": { "properties": { "data": { "required": ["id", "name"] } } }
}
}
}
},
"flows": {
"web": {
"destinations": {
"ga4": {
"validate": {
"events": "$contract.default.events",
"schema": "$contract.default.schema"
}
}
}
}
}
}
$store. — store wiring
Inject a store instance declared under stores. Wired through a component's
env so the bundler can resolve to the real store at build time.
{
"flows": {
"server": {
"stores": {
"cache": { "package": "@walkeros/server-store-fs" }
},
"sources": {
"http": {
"package": "@walkeros/server-source-http",
"env": { "store": "$store.cache" }
}
}
}
}
}
Store IDs are plain identifiers (camelCase). The . is the separator, not a
path walker, store IDs do not contain dots.
$secret. — secrets
Inject a secret resolved at deploy time. Secrets are stored outside the config and never written into customer databases alongside the flow.
{
"flows": {
"web": {
"destinations": {
"api": {
"config": {
"settings": {
"headers": { "Authorization": "Bearer $secret.API_TOKEN" }
}
}
}
}
}
}
}
Secret names are uppercase: [A-Z0-9_]+. The . is the separator, secrets
have no internal structure.
$code: — inline code
Embed a JavaScript function as a string. The bundler compiles the payload into
real JS at build time. Everything after $code: is the raw function body.
{
"variables": {
"onlyProducts": {
"condition": "$code:(entity) => entity.entity === 'product'"
}
}
}
The : here marks the payload. Nothing after the colon is looked up, it
is compiled as-is.
Cascade and resolution order
variables can live at three levels. Priority (highest wins):
- Step level (
sources.*,transformers.*,destinations.*,stores.*) - Flow level (
flows.<name>.variables) - Config root (
variables)
Resolution runs at getFlowSettings() in @walkeros/core, the runtime
replaces every reference before the bundler or collector sees the config.
What else to read
@walkeros/corereference exports:REF_VAR_FULL,REF_VAR_INLINE,REF_ENV,REF_CONTRACT,REF_FLOW,REF_STORE,REF_SECRET,REF_CODE_PREFIX. The single source of truth for the regex patterns. Also exportsscanFlowRefs(value)which walks any value (string, array, object) and returns every$flow.<name>reference found, including refs nested inside$code:snippets.- Stores guide: wiring stores via
$store.. - Mapping guide:
$code:and mapping-value shortcuts.