Parallel Window

The Parallel Window block is a container that processes a collection, a fixed number of repetitions, or named branches with a bounded number of items active at a time. A new item starts when one finishes, and the results keep the input order.

Use a Parallel Window when a collection is too large for the Parallel block (more than 20 items). Also use it when the body calls an API that cannot take every item at once. It accepts up to 1,000 items and runs between 1 and 20 of them concurrently.

Configuration Options

Run For

Choose the source of work:

ModeWhen to use it
CollectionRun the same body for each input, including calling the same child workflow with different inputs.
CountRun the same body a fixed number of times without building an input array. Enter an integer from 0 to 1,000.
BranchesRun different workflows or chains once each. Add named branches, assign every body block to exactly one branch, and select a result for each branch.

In Count mode, <parallel.currentItem> and <parallel.index> are the zero-based repetition index. In Branches mode, <parallel.currentItem> contains the branch's id and name. Results follow the configured order, and branch results include a stable branchId.

Branches can each contain a Workflow block plus their own follow-up blocks. Keep connections and references within a branch. Assign a Loop container to a branch to include all of its descendants. The canvas outlines each branch; use Move up in the editor to change its order. Empty collections, a count of zero, and an empty branch list with no body blocks produce empty results.

In Count mode, Number of runs saves when you leave the field or press Enter. You can clear the field while replacing the number. An empty, fractional, negative, or out-of-range value shows an error and leaves the saved count unchanged. Press Escape to restore the saved count.

Items

In Collection mode, the collection to process. Enter a JSON array directly or a single reference that resolves to an array, such as <api.data> or <start.input.leads>. Anything else fails the block before any item runs with parallel_window items must be a JSON array or an array reference or parallel_window items must resolve to an array.

The collection may hold up to 1,000 items. With a valid concurrency limit, an empty collection skips the body. The block then outputs an empty results array and total: 0, and the workflow continues.

Maximum Active Items

How many items run at the same time, from 1 to 20 (default 5). When an item finishes, the next queued item starts in its place, so the number of in-flight items never exceeds this value.

Enter a fixed integer or one upstream output reference, such as <start.concurrency> or <settings.result.concurrency>. Connect the source block upstream of the window so its output is available before any item starts. The reference must identify one unambiguous block. References to the window itself, body blocks, downstream or unconnected blocks, workflow variables, and expressions such as <start.concurrency> + 1 are rejected.

In the editor, a valid value saves when you leave the field or press Enter. Escape restores the saved value. An unfinished or invalid entry shows an error and does not replace the saved limit.

The resolved output must be a number and an integer from 1 to 20. An output that is still a string such as "4", a missing value, null, a boolean, a fraction, or an out-of-range number fails before any item starts, including for an empty collection. An invalid reference or value never falls back to 5. Unhandled item errors applies only after admission; choosing Record failure and continue does not make an invalid limit acceptable.

Each window captures its limit once and keeps that number through refills and checkpoint recovery. Changing the source output does not resize an active window. The limit applies to this window in one workflow run; simultaneous runs each have their own limit. It does not impose a requests-per-second limit on an API.

Choosing the Limit Through a Workflow Input

  1. In the Start block's Input Format, add an items field of type Array and a concurrency field of type Number. Set a default such as 5 on concurrency if callers may omit it.
  2. Connect Start to the Parallel Window. Set Items to <start.items> and Maximum active items to <start.concurrency>.
  3. Supply the inputs when running the workflow. For example, this input admits at most two items at a time:
{
  "items": [{ "id": "a" }, { "id": "b" }, { "id": "c" }],
  "concurrency": 2
}

Use the actual name of your Start block in the references. Start converts Number inputs before publishing its output, so a caller's numeric string can become a valid number there. The window itself does not coerce strings. For a calculated limit, compute and validate the number in an upstream block and reference its output, for example <settings.result.concurrency>.

Item Result

Exactly one <block.field> reference to a block inside the window, for example <finish.result>. Its value for each item becomes that item's value in the window's results.

The reference must point at a body block. If that block did not run for an item (for example a Condition routed around it), the item fails with Item result block did not execute. If the referenced field is missing, the item fails with Item result did not resolve. A field that is explicitly null is kept as null.

Unhandled Item Errors

What happens when a block inside an item fails and no error path handles it:

  • Stop the window (default): the first unhandled error fails the Parallel Window block and the workflow run.
  • Record failure and continue: the error becomes a rejected cell for that item. The rest of that item's body is skipped, and the remaining items still run.

How to Use Parallel Windows

Creating a Parallel Window

  1. Drag a Parallel Window block from the toolbar onto your canvas
  2. Choose Run for: set Items for Collection, Number of runs for Count, or add named branches for Branches
  3. Drag the blocks that should run for each item inside the container
  4. Connect the blocks as needed
  5. Set Item result to the output of the last block in the body, for example <finish.result>. In Branches mode, assign every body block to one branch and set each Branch result instead
  6. Choose Maximum active items
  7. Choose how to treat Unhandled item errors

Referencing Parallel Window Data

Inside the window, use <parallel.> references to access the current item:

  • <parallel.index>: Position of this item in the collection (0-based)
  • <parallel.currentItem>: The item being processed
  • <parallel.items>: The full collection
// Inside a Function block within the window
const idx = <parallel.index>;           // 0, 1, 2, ...
const item = <parallel.currentItem>;    // This item

Body blocks can also reference blocks that ran before the window and body blocks earlier in the same item. They cannot read the window's own results, total, completed, active, or queued. Those values are not final until every item has settled.

Example Use Cases

Rate-Limited Enrichment - Enrich hundreds of records without exceeding an API's concurrency limit

API (Fetch 500 leads) → Parallel Window (5 active) → API (Enrich) → Function (Normalize) → Table (Insert results)

Bulk Notifications - Send one message per row while keeping a handful of requests in flight

Table (Query rows) → Parallel Window (10 active) → Slack (Post) → Function (Summarize failures)

Advanced Features

Body Restrictions

SteelEngine validates a Parallel Window before the run starts. If the body breaks a rule, it fails the run with parallel_window <id>: <reason>. Inside the window you can use sequential Loop containers (including loops within loops), Function, API, Condition, Router, JSON Mapper, Workflow, and integration blocks (third-party service blocks such as Gmail or Slack). Other block types are rejected, including Agent, Evaluator, Knowledge, Table, Variables, Wait, Human in the Loop, and Response. Document generation is also rejected.

The following are also rejected:

  • Unsupported nesting: a Parallel or Parallel Window inside the body, or a Parallel Window placed inside a Loop or Parallel. Sequential Loop containers inside a window are supported; the same block restrictions apply to every descendant
  • Connections that cross the boundary: every connection from a body block must stay inside the window. Body blocks can only be entered from the window
  • Disabled body blocks: enable or delete them
  • References out of the body: a block outside the window that references a body block's output
  • Concurrent variable writers: a Variables block anywhere in the workflow that does not run strictly before or strictly after the window. Workflow variables are shared across the whole run, so they cannot be written while items run concurrently

Child Workflows Inside a Window

Put a Workflow block inside the body and map its inputs from the current item, index, or upstream outputs. Each child finishes and records its completion independently. Follow-up blocks in the same item can then run immediately. The item keeps its slot until its entire chain finishes, and the parent waits for all items before exposing the final aggregate.

For example, if 19 children finish in 3 seconds and one takes 19 seconds, the fast children can log their completion and run their reporting blocks at 3 seconds. Queued items can start as slots become free. The parent still finishes after the last item settles. Place reporting inside the body for per-child reporting, or after the window for a final summary.

For 20 different child calls, select Branches, add one branch per call, and assign each call and its reporting blocks to that branch. For one child called with 20 inputs, use Collection. Use Count when only the repetition index is needed.

Child workflows retain their own variables, Response, loops, and ordinary Parallel containers. Response finishes only that child. Within one item, child blocks execute one at a time to preserve the window's concurrency limit. With TEMPORAL_PARALLEL_WINDOW_CHAINS enabled, a child's consecutive blocks run back to back in one step instead of waiting for a window round between blocks; results, logs and order are the same. With TEMPORAL_PARALLEL_WINDOW_ITEM_STATE enabled, each item's steps are applied to that item's own state instead of to every item in flight, so a window with more items in flight or larger outputs advances faster; results, logs and order are again the same. Children containing Wait, Human in the Loop, document generation, or another Parallel Window are rejected before that child's business blocks run. The same restrictions apply to nested child calls.

These remain inline children of the parent, so cancelling the parent cancels its active work. They do not become detached runs. Existing workspace, draft/deployed version, and nesting rules still apply. An unhandled child failure follows the window's error setting; a connected error path can recover within the item.

Loops Inside a Window

Each active item owns its complete loop state. <parallel.currentItem> identifies the window item and <loop.currentItem> identifies the current element of the innermost loop. Named loop references can access enclosing loop context. Another item can advance while this item processes its next iteration.

A loop's collection is evaluated before that loop starts. Use the window item, an upstream output, or an enclosing loop's context for the collection. A loop directly inside the window cannot use <loop.items> as its own collection. While and Do While conditions can read their current loop's context, the window item, and outputs from earlier blocks in the same item. For example, <loop.index> < <parallel.currentItem.limit> uses each item's own limit. Blocks inside a loop cannot read that enclosing loop's result or results until it has completed.

The item retains its concurrency slot through all loop iterations and subsequent blocks. Place a final Function block after the loops and select that block's output as Item result. A block inside a loop cannot be selected as the item result because it can execute multiple times. Read a completed loop through its aggregate output instead of referencing an individual nested block from outside that loop.

With TEMPORAL_PARALLEL_WINDOW_CHAINS and TEMPORAL_PARALLEL_WINDOW_CHAIN_LOOP_CONTROL enabled, an item runs through its loops' starts, iterations and ends in one step instead of waiting for a window round at each of them, so items with loops finish sooner. Each loop decision, including a While or Do While condition, is evaluated once and reused; results, logs and order are the same.

An empty loop still proceeds to the item's remaining blocks. An unhandled error inside a loop follows the window's error policy; connect explicit error paths when recovery should continue within the item. Record failure and continue skips the remainder of the failed item, including any unexecuted reporting block.

All Workers must support nested window loops before deploying such a workflow. Existing ordinary Parallel blocks and flat Parallel Windows retain their scheduling behaviour.

Failure Handling

With Stop the window, the first unhandled error in any item fails the block and the workflow. Queued items never start. With Record failure and continue, the failed item is recorded as { index, status: 'rejected', error }. The remaining blocks in that item are skipped, and the other items keep running. The window still completes, and downstream blocks decide what to do with the rejected cells. An Item result that cannot be resolved counts as an unhandled error and follows the same setting.

An error path connected to a body block handles the error inside the item. Only unhandled errors reach this setting.

Limitations

The collection is limited to 1,000 items and the window to 20 active items. Larger inputs fail the block before any item runs. Nested windows are not supported.

Parallel Window vs Parallel

FeatureParallel WindowParallel
Work sourcesCollection, Count, or named BranchesCount or Collection
Collection sizeUp to 1,000 itemsUp to 20 instances
Concurrency1-20 items active, refilled as items finishAll instances at once
BodyFunction, API, Condition, Router, JSON Mapper, integration blocks, Workflow calls and sequential LoopsAny blocks, including nested Loops and Parallels
ResultsFlat array, one settled cell per itemOne array of settled cells per instance
FailuresStop the window or record and continueAlways recorded as rejected cells

Inputs and Outputs

  • Run for: Collection, Count, or Branches. In Collection mode, Items is a JSON array or a reference that resolves to an array (up to 1,000 items). In Count mode, Number of runs is an integer from 0 to 1,000. In Branches mode, assign body blocks to named branches that each run once

  • Maximum active items: Integer from 1 to 20 (default 5), or one upstream output reference resolving to that integer

  • Item result: One <block.field> reference to a body block. In Branches mode, set a Branch result for each branch instead

  • Unhandled item errors: 'Stop the window' or 'Record failure and continue'

Best Practices

  • Size the window to the slowest dependency: Match Maximum active items to the concurrency the body's API tolerates rather than the maximum of 20
  • End the body with one block: Route every path in the item to a final Function block. Point Item result at it, so the result resolves for every item
  • Record and continue for bulk work: Choose Record failure and continue when one bad item should not discard the rest. Inspect the rejected cells downstream
  • Keep parent variable writes outside: Read workflow variables inside the body if you need them, but place parent Variables blocks before or after the window. Child workflows may write their own local variables

Common Questions

A Parallel block runs every instance at once and is limited to 20. A Parallel Window accepts up to 1,000 items and keeps only a bounded number (1 to 20) running. It starts the next item as soon as one finishes. Its results are a flat array with one settled cell per item. It also lets you choose whether an unhandled item error stops the window or is recorded so the other items continue.
Yes. Each cell carries the item's index, and SteelEngine assembles the results array by index. So results[0] is the first item regardless of which item finished first.
It depends on Unhandled item errors. With 'Stop the window', the first unhandled error fails the block and the workflow run. With 'Record failure and continue', the item becomes a { index, status: 'rejected', error } cell. The rest of that item's blocks are skipped, and the remaining items still run. Errors handled by an error path inside the item do not count as unhandled.
Sequential Loops, Function, API, Condition, Router, JSON Mapper, Workflow calls, and integration blocks such as Gmail or Slack. Validation rejects Agent, Evaluator, Knowledge, Table, Variables, Wait, Human in the Loop, and Response blocks before the run starts. Sequential Loop containers are supported, including loops within loops; their descendants have the same block restrictions. Nested Parallel and Parallel Window blocks are rejected.
No. A Parallel Window must sit at the top level of the workflow, and it can contain sequential Loops, but cannot contain Parallel or Parallel Window containers. The workflow fails validation with 'nested windows are not supported' otherwise.
Workflow variables are shared across the whole run. A Variables block that could run at the same time as the window would race with the items. So every Variables block must run strictly before or strictly after the window. Move it upstream of the window or connect it after the window's exit.
It names the single value that represents each item, as one <block.field> reference to a block inside the window. That value becomes the item's value in results. If the referenced block did not run for an item, the item fails with 'Item result block did not execute'. If the field is missing, the item fails with 'Item result did not resolve'.

On this page