Portal Community
PropertyValue
Directive namevar
Required isolation levelSafe
ProjectMemory.Services
Data sourceIExecutionMemory — keyed by ExecutionId + VariableName
Also: default directiveExpressions without a $directive prefix route here by default

Syntax

Named variable
{@ $var.variableName }
Nested path inside a JSON object variable
{@ $var.customer.address.city }
Array index
{@ $var.lineItems[0].unitPrice }
Default directive (no $prefix) — routes to $var
{@ invoiceTotal }

Variable Scoping

Variables are scoped to the execution. The IExecutionMemory interface supports multiple scope levels:

ScopePath prefixLifetime
Local (default)$var.nameCurrent execution only
Flow-level$var.flow.nameShared across sub-workflows
Global$var.global.namePersisted 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

OptionUse case
@uppercase @lowercase @trimString normalization
@jsonSerialize object/array variable to JSON string
@base64Encode variable content for safe transport
@default:valEssential — variables may not be set if an upstream node failed or was skipped
@requiredForce failure if variable is missing (prevent silent empty values)
@cacheCache 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:

HTTP body template
{
  "executionId": "{@ $exec.executionId }",
  "customer": {@ $var.customer @json },
  "invoice": {@ $var.invoice @json }
}
{ "executionId": "e8f2...", "customer": {...}, "invoice": {...} }

Common Errors

ErrorCauseFix
PathNotFound: myVarVariableAssignment node upstream didn't run or set a different nameCheck node execution order; use @default:fallback
PathNotFound: customer.contacts[5]Array index out of boundsValidate array length with $js before accessing
Returns null instead of nested valueVariable stored as string (not parsed JSON)Ensure the storing node uses @json option or stores a parsed object