Control Flow Nodes

Control flow nodes determine how data moves through your workflow. Use them to branch, loop, run tasks in parallel, pause execution, handle errors, and compose workflows from reusable subflows.

All Control Flow Nodes

If/ElseLogic

Evaluate a condition and route data to the True or False branch. Supports expressions, comparisons, and boolean logic.

SwitchLogic

Multi-way branching based on a value. Define named cases with match conditions and an optional default fallthrough branch.

LoopLogic

Iterate over an array and execute downstream nodes once per item. Access the current item, index, and total count in expressions.

ParallelLogic

Execute multiple downstream branches concurrently. All branches run simultaneously and results are collected when every branch completes.

DelayLogic

Pause workflow execution for a specified duration. Configure delays in seconds, minutes, or hours.

Try/CatchLogic

Wrap nodes in error handling. The Try branch executes normally; if any node throws an error, execution jumps to the Catch branch. An optional Finally branch runs regardless of success or failure.

SubflowLogic

Execute another workflow as a step within the current workflow. Enables modular, reusable workflow design with input/output data mapping.

CodeLogic

Run custom JavaScript or Python code in a sandboxed Docker container. Process, transform, or generate data with full programming flexibility.

If/Else Condition

The If/Else node evaluates one or more conditions and directs data down the True or False output. Conditions are defined as a JSON array, and you can combine multiple conditions with AND or OR logic.

Parameters

NameTypeDefaultDescription
conditionsarrayrequiredArray of condition objects. Each condition has a field, operator, and value. See the operator reference below.
combineWithstring"and"How to combine multiple conditions: "and" (all must be true) or "or" (any must be true).

Supported Operators

OperatorDescription
equalsExact string or number match
notEqualsValue is not equal
greaterThanNumeric greater than
greaterThanOrEqualNumeric greater than or equal
lessThanNumeric less than
lessThanOrEqualNumeric less than or equal
containsString contains substring
notContainsString does not contain substring
startsWithString starts with prefix
endsWithString ends with suffix
isEmptyValue is null, undefined, or empty string
isNotEmptyValue is present and non-empty
matchesRegexValue matches a regular expression
notMatchesRegexValue does not match regex
isInValue is in a comma-separated list
isNotInValue is not in a comma-separated list
isTrueValue is truthy (true, 1, "true")
isFalseValue is falsy (false, 0, "false")
existsField exists in the data
notExistsField does not exist in the data

Example

If/Else condition configuration
{
  "conditions": [
    {
      "field": "{{ $json.status }}",
      "operator": "equals",
      "value": "active"
    },
    {
      "field": "{{ $json.score }}",
      "operator": "greaterThan",
      "value": 80
    }
  ],
  "combineWith": "and"
}

Switch

The Switch node provides multi-way branching. Define a value expression and one or more cases. Each case creates a separate output port on the node, allowing you to route data to different downstream branches.

Parameters

NameTypeDefaultDescription
valuestringrequiredExpression to evaluate (e.g. {{ $json.region }}). The result is matched against each case.
casesarrayrequiredArray of case objects. Each case has a name and a value to match against. Each case creates a dynamic output port.
modestring"exact"Match mode: "exact" (strict equality), "contains" (substring match), or "regex" (regular expression match).

Example

Switch configuration
{
  "value": "{{ $json.region }}",
  "cases": [
    { "name": "US East", "value": "us-east-1" },
    { "name": "US West", "value": "us-west-2" },
    { "name": "EU", "value": "eu-west-1" },
    { "name": "Default", "value": "*" }
  ],
  "mode": "exact"
}

Dynamic output ports

Each case in the Switch node creates its own output port on the canvas. Connect downstream nodes to individual case ports to build separate processing branches per case value.

Subflow

The Subflow node executes another workflow as a step within the current workflow. This enables modular workflow design. Build reusable logic once and invoke it from multiple parent workflows.

Parameters

NameTypeDefaultDescription
workflowIdstringrequiredID of the workflow to execute as a subflow. Select from the searchable dropdown.
inputMappingobject{}Map data from the parent workflow into the subflow's trigger input. Keys are subflow input field names, values are expressions.
outputMappingobject{}Extract fields from the subflow's final output back into the parent workflow's data.
timeoutnumber60000Maximum time (ms) to wait for the subflow to complete before failing.
passCredentialsbooleanfalseWhether to pass the parent workflow's credential context to the subflow.

Example

Subflow configuration
{
  "workflowId": "wf_abc123",
  "inputMapping": {
    "customerEmail": "{{ $json.email }}",
    "orderId": "{{ $json.orderId }}",
    "items": "{{ $json.lineItems }}"
  },
  "outputMapping": {
    "confirmationNumber": "{{ $json.confirmation }}",
    "estimatedDelivery": "{{ $json.deliveryDate }}"
  },
  "timeout": 30000,
  "passCredentials": true
}

Recursion depth

NodeLoom enforces a maximum subflow nesting depth of 10. If workflow A calls B which calls C (and so on), the chain cannot exceed 10 levels. Design your subflow hierarchy to stay well within this limit.

Code

The Code node lets you run custom JavaScript or Python code to process, transform, or generate data. All code executes in a sandboxed Docker container for security. The sandbox is mandatory and cannot be disabled.

Parameters

NameTypeDefaultDescription
codestringrequiredThe code to execute. Has access to the items variable containing input data from upstream nodes.
modestring"javascript"Programming language: "javascript" or "python".

The items API

Your code receives an items array containing input data from upstream nodes. Each item is a JSON object. Your code must return an array of items as the output.

Code node example
// JavaScript example: transform and filter items
const results = [];

for (const item of items) {
  // Access input fields
  const name = item.json.name;
  const score = item.json.score;

  // Filter: only keep items with score > 50
  if (score > 50) {
    results.push({
      json: {
        name: name.toUpperCase(),
        score: score,
        grade: score >= 90 ? "A" : score >= 80 ? "B" : "C",
        processedAt: new Date().toISOString()
      }
    });
  }
}

return results;

Docker sandbox

Code nodes always run in a Docker sandbox. This is mandatory and server-enforced. The sandbox restricts network access, filesystem access, and execution time. You cannot import external packages.

Loop

The Loop node iterates over an array and executes downstream nodes once for each item. Inside the loop body, you can access:

  • {{ $json.item }}, the current array element
  • {{ $json.index }}, the zero-based iteration index
  • {{ $json.total }}, the total number of items

Parallel

The Parallel node splits execution into concurrent branches. All branches start simultaneously and the node waits for every branch to complete before merging results and continuing the workflow.

Execution limits

Parallel branches share the same execution context. Be mindful of rate limits when making external API calls across many branches.

Delay

The Delay node pauses execution for a configurable duration. Use it to add wait times between API calls (rate limiting), schedule follow-up actions, or implement polling patterns.

Try/Catch

The Try/Catch node wraps a group of nodes in error handling. If any node in the Try branch throws an error, execution immediately jumps to the Catch branch. The Catch branch receives the error details. An optional Finally branch always executes, regardless of whether an error occurred.

BranchExecutes When
TryAlways. Contains the primary logic.
CatchOnly when an error occurs in the Try branch.
FinallyAlways. Runs after Try or Catch completes.