Portal Community
ParallelFork and ParallelJoin must be used together. Fork opens the parallel lanes; Join closes them and collects all lane outputs into a single execution point. Every branch connected to the Fork's success port must eventually lead to the paired Join node.

When to Use

Configuration

FieldRequiredDescription
FailFast Optional Default false. When true, if any single lane fails (throws an unhandled error), all remaining running lanes are cancelled immediately and the parallel block routes to the Join's error port. Use for operations that must all succeed together — e.g. financial debit/credit pairs.
MaxParallelism Optional Default 0 (unlimited). When set to a positive integer, at most that many lanes run simultaneously. Excess lanes queue and start as running lanes complete. Use when downstream APIs enforce rate limits on concurrent connections.

Output Ports

PortDescription
successFires to launch all connected parallel lanes. Every node or branch connected to this port starts execution concurrently. Connect each lane's starting node here.

OutputData Fields

Available downstream via $output.<forkNodeKey>:

FieldTypeDescription
fork_idstringThe node key of the Fork node — used by the paired Join to identify which parallel block to collect results for.
lanes_initializedstringISO 8601 timestamp of when the parallel lanes were launched.

Sample Configuration

Three-channel notification fork

{
  "FailFast": false,
  "MaxParallelism": 0
}

Rate-limited API fan-out (max 2 concurrent)

{
  "FailFast": false,
  "MaxParallelism": 2
}

Critical paired operations (fail-fast enabled)

{
  "FailFast": true,
  "MaxParallelism": 0
}

Validation Errors

ErrorCause
VAL_INVALID_MAX_PARALLELISMMaxParallelism is a negative integer. Must be 0 (unlimited) or a positive integer.

Sample Output

All Branches Port (after all parallel branches complete)

ParallelFork fans out execution to multiple branches simultaneously. When all branches complete, their outputs are collected and available downstream.

{
  "_fork": {
    "branchCount": 3,
    "completedBranches": 3,
    "failedBranches": 0,
    "totalDurationMs": 1847,
    "longestBranchMs": 1650
  },
  "branches": {
    "fetchInventory": {
      "status": "completed",
      "output": { "totalItems": 1432, "lowStockCount": 12 }
    },
    "fetchPricing": {
      "status": "completed",
      "output": { "priceListVersion": "2025-03", "updatedCount": 89 }
    },
    "fetchSuppliers": {
      "status": "completed",
      "output": { "activeSuppliers": 24, "pendingOrders": 7 }
    }
  }
}

Expression Reference

ExpressionDescription
{{ $output.forkNode._fork.branchCount }}Number of parallel branches that were forked.
{{ $output.forkNode._fork.failedBranches }}Number of branches that errored. Check before proceeding.
{{ $output.forkNode.branches.fetchInventory.output.totalItems }}Output from a named branch — access by branch name then field path.
{{ $output.forkNode._fork.totalDurationMs }}Total wall-clock time for all branches to complete.

Node Policies and GuardRails

Pattern Examples

Pattern 1 — Multi-Channel Order Confirmation

On order confirmation, dispatch notifications via all three channels simultaneously. Total wait time is the slowest channel, not the sum of all three.

FormTrigger  (order confirmed)
  └─► ParallelFork  [key: "notifyFork"]
        FailFast: false
        └─► success ──┬── EmailSmtp        [lane A]
                      │     To: {{ $json.customer.email }}
                      │
                      ├── SlackNode        [lane B]
                      │     Channel: #orders-team
                      │
                      └── HttpRequest      [lane C]
                            POST /sms/send {{ $json.customer.phone }}
  [all three connect to] ──► ParallelJoin  [key: "notifyJoin"]
                               └─► success ──► [continue workflow]

Pattern 2 — Concurrent API Enrichment

Enrich a loan application by calling three independent data sources in parallel. After all respond, the Join merges all results and a downstream node makes the approval decision.

WebhookTrigger  (loan application received)
  └─► ParallelFork  [key: "enrichFork"]
        FailFast: true
        └─► success ──┬── HttpRequest  [key: "creditCheck"]
                      │     GET /credit-bureau/score/{{ $json.applicantId }}
                      │
                      ├── HttpRequest  [key: "fraudCheck"]
                      │     GET /fraud-service/risk/{{ $json.applicantId }}
                      │
                      └── HttpRequest  [key: "incomeCheck"]
                            GET /income-verify/{{ $json.applicantId }}
  [all three connect to] ──► ParallelJoin  [key: "enrichJoin"]
  └─► success
        creditScore:  {{ $output.enrichJoin.lane_outputs.lane_creditCheck.score }}
        fraudRisk:    {{ $output.enrichJoin.lane_outputs.lane_fraudCheck.riskLevel }}
        verifiedIncome: {{ $output.enrichJoin.lane_outputs.lane_incomeCheck.annual }}

Pattern 3 — Rate-Limited Batch Fan-Out

Process items in batches with a maximum of 2 concurrent lanes to respect the downstream API's rate limit of 2 concurrent requests.

ParallelFork  [key: "batchFork"]
  FailFast: false
  MaxParallelism: 2
  └─► success ──┬── [Lane A: process batch 1]
                ├── [Lane B: process batch 2]
                ├── [Lane C: process batch 3]  (queues until A or B completes)
                └── [Lane D: process batch 4]  (queues until a slot opens)
  ──► ParallelJoin  [key: "batchJoin"]