$var — Variable Directive
Reads variables stored in workflow execution memory. Supports dot-path navigation into nested JSON objects and arrays.
| Property | Value |
|---|---|
| Directive name | var |
| Required isolation level | Safe |
| Project | Memory.Services |
| Data source | IExecutionMemory — keyed by ExecutionId + VariableName |
| Also: default directive | Expressions without a $directive prefix route here by default |
Syntax
Variable Scoping
Variables are scoped to the execution. The IExecutionMemory interface supports multiple scope levels:
| Scope | Path prefix | Lifetime |
|---|---|---|
| Local (default) | $var.name | Current execution only |
| Flow-level | $var.flow.name | Shared across sub-workflows |
| Global | $var.global.name | Persisted beyond execution (tenant-scoped) |
Path Navigation
The path after the variable name navigates into the stored JSON value using JsonPathResolver:
// Variable "customer" contains:
{
"name": "Acme Ltd",
"address": { "city": "Dublin", "country": "IE" },
"contacts": [
{ "name": "Alice", "role": "billing" },
{ "name": "Bob", "role": "technical" }
]
}
// Expressions:
{@ $var.customer.name } → "Acme Ltd"
{@ $var.customer.address.city } → "Dublin"
{@ $var.customer.contacts[0].name } → "Alice"
{@ $var.customer.contacts[1].role } → "technical"
{@ $var.customer.address @json } → '{"city":"Dublin","country":"IE"}'
Options Compatibility
| Option | Use case |
|---|---|
@uppercase @lowercase @trim | String normalization |
@json | Serialize object/array variable to JSON string |
@base64 | Encode variable content for safe transport |
@default:val | Essential — variables may not be set if an upstream node failed or was skipped |
@required | Force failure if variable is missing (prevent silent empty values) |
@cache | Cache within the node — useful if the same variable is read many times in one node |
Complex Scenarios
Scenario 1 — Invoice Line Items Summary
A VariableAssignment node stores a complex object; downstream nodes read specific fields:
// VariableAssignment node sets "invoice":
{
"number": "INV-2024-001",
"lineItems": [
{ "description": "Consulting", "qty": 5, "unitPrice": 150, "total": 750 },
{ "description": "License", "qty": 1, "unitPrice": 2000, "total": 2000 }
],
"subtotal": 2750,
"tax": 550,
"total": 3300
}
// Email subject node:
Invoice {@ $var.invoice.number } — {@ $var.invoice.total } {@ $ctx.tenant.currency }
// HTTP body: send first line item description to ERP
{@ $var.invoice.lineItems[0].description }
Scenario 2 — Accumulating a Running Total Across Loop Iterations
In a Loop node processing batch records, accumulate a running total in a variable:
// Node 1: Initialize (before loop)
VariableName: "runningTotal" Value: "0"
// Node 2: Inside loop — JavaScript update
{@ $js`
return parseFloat(context.vars.runningTotal || 0)
+ parseFloat(context.input.current.amount || 0);
` }
// Store result back to "runningTotal"
// Node 3: After loop — use accumulated total
Total processed: {@ $var.runningTotal } {@ $ctx.tenant.currency }
Scenario 3 — Passing Data Between Sub-workflows
Use $var.flow.* scope to share data with a sub-workflow:
// Parent workflow sets flow-scoped variable
VariableName: "flow.customerTier" Value: "{@ $input.current.tier }"
// Sub-workflow reads it (flow scope is inherited)
{@ $var.flow.customerTier }
// "gold" — inherited from parent scope
Scenario 4 — Feature Flag / Config Toggle
Store feature flags as global variables, read them across all executions:
// Global variable "global.featureFlags" set by admin:
{ "newInvoiceEngine": true, "legacyExport": false, "betaDashboard": true }
// Workflow reads the flag:
{@ $var.global.featureFlags.newInvoiceEngine }
// → true → IfCondition routes to new engine branch
Scenario 5 — Defensive Reading with Default and Required
Ensure critical variables are set, provide safe defaults for optional ones:
// Required: fail fast if approver was never set
{@ $var.approverEmail @required }
// Optional: use 14 days if payment terms not set
{@ $var.paymentTermsDays @default:14 }
// Optional string: display "N/A" if reference not provided
{@ $var.purchaseOrderRef @default:N/A @trim @uppercase }
Scenario 6 — Embedding a Variable Object into a JSON Payload
A variable holds an object that must be embedded as-is into an HTTP request body:
"executionId": "{@ $exec.executionId }",
"customer": {@ $var.customer @json },
"invoice": {@ $var.invoice @json }
}
Common Errors
| Error | Cause | Fix |
|---|---|---|
PathNotFound: myVar | VariableAssignment node upstream didn't run or set a different name | Check node execution order; use @default:fallback |
PathNotFound: customer.contacts[5] | Array index out of bounds | Validate array length with $js before accessing |
Returns null instead of nested value | Variable stored as string (not parsed JSON) | Ensure the storing node uses @json option or stores a parsed object |