VariableAssignment NodeTypeCode: variable-assignment
Store a named value into workflow execution memory. Assigned variables are accessible from any downstream node using the {{ $var.variableName }} expression syntax.
When to Use
- Initialize a counter at 0: Before entering a Loop node, assign
processedCount=0. Increment it inside the loop body using a subsequent VariableAssignment withValueExpression={{ $var.processedCount + 1 }}. - Store the current UTC timestamp: Capture
runStartedAtat the beginning of a batch workflow using a CodeExecute node to getnew Date().toISOString(), then assign it via VariableAssignment. Reference it in final log entries to calculate total run duration. - Capture a computed value for multiple uses: An HTTP call returns an API response with a deeply nested customer tier. Assign it once to
customerTierand reference it in three downstream nodes — Switch, Email subject line, and database write — without re-fetching or re-navigating the nested path each time. - Set a flag based on a condition: After an Approval node, assign
isApproved=trueon the approved port andisApproved=falseon the rejected port. Downstream nodes branch on{{ $var.isApproved }}without needing to know the approval node's output structure. - Save an ID from a previous node: A database insert returns a new record ID. Assign it to
newInvoiceIdimmediately so multiple subsequent nodes — a PDF generator, an email sender, and an audit logger — can all reference the same ID consistently.
Configuration
| Setting | Required | Description |
|---|---|---|
VariableName |
Required | The name under which the value is stored in workflow memory. Must be a valid identifier (letters, numbers, underscores; no spaces). Case-sensitive. Example: customerTier, invoiceId, processedCount. |
Value |
Optional | A constant literal value to assign. Can be a string ("active"), number (0), or boolean (false). Used when the value does not depend on runtime data. Takes lower priority than InputData values. |
ValueExpression |
Optional | A BizFirst expression that is evaluated at runtime to produce the value. Examples: {{ $output.prevNode.customerId }}, {{ $var.counter + 1 }}, {{ $output.apiNode.data.address.city | uppercase }}. Takes lower priority than InputData values but higher than the Value constant. |
Value Resolution Priority
When multiple sources are available, the node resolves the value in this order (first match wins):
InputData["value"]— if the preceding node explicitly passes a field namedvaluein its output, that takes priority.InputData["value_expression"]— if the preceding node passes a field namedvalue_expression, it is evaluated as an expression.Settings.Value— the constant value configured in the node settings.Settings.ValueExpression— the expression configured in the node settings.
ValueExpression in settings to reference an upstream node output (e.g., {{ $output.httpNode.data.id }}). The InputData priority mechanism is an advanced pattern for dynamic assignment from loop bodies or parallel branches.
Output Ports
| Port | When It Fires |
|---|---|
success | The value was successfully resolved and stored in workflow memory. Downstream nodes can immediately read the variable using {{ $var.variableName }}. |
error | The expression in ValueExpression fails to evaluate (e.g., references a non-existent node output or contains a syntax error). The variable is not stored. Downstream nodes reading this variable will receive null. |
Output Fields
| Field | Type | Description |
|---|---|---|
assigned_variable | string | The name of the variable that was assigned (same as VariableName setting). Useful for dynamic logging. |
assigned_value | any | The resolved value that was stored. Note: use {{ $var.variableName }} in downstream nodes — NOT {{ $output.nodeName.assigned_value }} — as variable memory is workflow-global while node output is positional. |
{{ $var.variableName }} from any downstream node — not via {{ $output.assignmentNode.assigned_value }}. The $var namespace is workflow-global; the $output namespace is node-positional (only accessible to immediately connected downstream nodes).
Sample Configurations
Constant value assignment
{
"nodeType": "variable-assignment",
"settings": {
"VariableName": "processingStatus",
"Value": "pending"
}
}
Dynamic expression assignment
{
"nodeType": "variable-assignment",
"settings": {
"VariableName": "customerId",
"ValueExpression": "{{ $output.crmLookup.data.customer.id }}"
}
}
Counter increment inside a loop
{
"nodeType": "variable-assignment",
"settings": {
"VariableName": "processedCount",
"ValueExpression": "{{ $var.processedCount + 1 }}"
}
}
Sample Output
Success Port
{
"assigned": {
"orderTotal": 1250.00,
"customerTier": "gold",
"discountRate": 0.15,
"processedDate": "2025-03-15",
"isEligibleForShipping": true
},
"variableCount": 5,
"_previousValues": {
"orderTotal": null,
"customerTier": null
}
}
Expression Reference
| Expression (in downstream nodes) | Value |
|---|---|
{{ $var.customerId }} | The value stored under the name customerId. Available from any subsequent node in the workflow. |
{{ $var.processedCount }} | The current value of the processedCount counter — updated each loop iteration. |
{{ $var.isApproved }} | A boolean flag set after an Approval node's decision ports. |
{{ $output.assignNode.assigned_variable }} | The name of the variable that was just assigned — useful for dynamic log messages. |
Node Policies & GuardRails
| Policy | Rationale |
|---|---|
| Use camelCase names for variables | Consistent naming makes workflows readable and maintainable. Use descriptive names like invoiceTotal, customerTier, runDate — not x, temp, or val1. |
Access variables with {{ $var.name }}, not {{ $output.nodeName.assigned_value }} | Variable memory is workflow-global and persists throughout the execution. Node output is positional and only available immediately after the producing node. Using the wrong access pattern causes null references in non-adjacent nodes. |
| Initialize counter variables before loops | Always assign a counter to 0 before the loop starts. Reading an uninitialized variable returns null, which breaks arithmetic expressions inside the loop body. |
| Connect the error port in expression assignments | If ValueExpression references a node output that doesn't exist yet (e.g., due to a conditional branch skipping that node), the assignment fails silently unless the error port is handled. Route error to a notification node. |
Pattern Examples
Pattern 1 — Capture New Record ID for Multi-Node Reuse
A database insert returns the new invoice record ID. Multiple downstream nodes (PDF generator, email, audit log) all need this ID — assign it once and reference everywhere.
// VariableAssignment after DB insert node
{
"VariableName": "newInvoiceId",
"ValueExpression": "{{ $output.dbInsertNode.insertedId }}"
}
// Downstream PDF generator references: {{ $var.newInvoiceId }}
// Downstream email node references: "Invoice #{{ $var.newInvoiceId }} is attached"
// Downstream audit log references: {{ $var.newInvoiceId }}
Pattern 2 — Set Approval Flag on Decision Ports
After an Approval node, set a boolean flag on both the approved and rejected ports. Downstream nodes branch on the flag without coupling to the Approval node's output structure.
// On 'approved' port of Approval node:
{
"VariableName": "approvalGranted",
"Value": true
}
// On 'rejected' port of Approval node:
{
"VariableName": "approvalGranted",
"Value": false
}
// Downstream IfCondition — clean expression on the flag:
// Condition: {{ $var.approvalGranted }} === true
Pattern 3 — Running Total Accumulator in a Loop
A loop iterates over invoice line items. A VariableAssignment inside the loop accumulates the running total for use in a summary node after the loop completes.
// Before loop — initialize
{
"VariableName": "invoiceTotal",
"Value": 0
}
// Inside loop body — increment
{
"VariableName": "invoiceTotal",
"ValueExpression": "{{ $var.invoiceTotal + $output.currentItem.lineAmount }}"
}
// After loop — reference in email subject
// "Invoice total: {{ $var.invoiceTotal }}"