Nodes/Kinburg-Nodes/For Each (Open)
ComfyUI Node

For Each (Open)

Run the graph once per frame, without the copy-paste

By Kinburg·Created 3 months ago·Updated 6 days ago· 1
For Each (Open)
  • value_0
  • value_1
  • value_2
  • value_3
  • value_4
  • value_5
  • value_6
  • value_7
  • value_8
  • value_9
  • value_10
  • value_11
  • value_12
  • value_13
  • value_14
  • value_15
  • value_16
  • value_17
  • value_18
  • value_19
  • flow
  • index
  • total
  • element_0
  • element_1
  • element_2
  • element_3
  • element_4
  • element_5
  • element_6
  • element_7
  • element_8
  • element_9
  • element_10
  • element_11
  • element_12
  • element_13
  • element_14
  • element_15
  • element_16
  • element_17
  • element_18
  • element_19

Every ComfyUI user hits the same wall eventually: you have a batch of images and you need to do something to each one individually - different crops, per-frame processing, a per-image pass of something that doesn't batch. The copy-paste answer is to duplicate a subgraph for every frame, which is insane beyond two frames. For Each (Open) is the loop opener that turns the graph between it and its sibling into a per-item processor: it fans a batch or list out one element at a time, ComfyUI runs the downstream graph once per element, and a For Each (Collect) on the other side gathers the results back.

The mechanism is the pack's honest take on loops in an acyclic engine: it's a map. The node declares OUTPUT_IS_LIST, so ComfyUI treats each of its outputs as a per-item stream and executes the downstream graph once per element, no state carried between items. Internally it flattens whatever arrives - an IMAGE batch becomes single frames, a Python list becomes its items, anything else becomes a one-item list - and hands the index-th element of each connected input to the graph on iteration index.

Inputs are the auto-growing value_* slots (up to 20, * type so any combination works). Outputs:

  • flow - the loop handle that wires to the matching Collect (the Auto-pair button connects it).
  • index / total - current iteration and how many iterations there are. Wiring index into a filename is how you get per-frame numbered outputs without any state.
  • element_0element_19 - this iteration's value for each connected input slot.

The pair is designed to be used as a unit: Open at the top of a region, Collect at the bottom, everything between them is the loop body. If you only want to read one element out of a batch rather than process every one, that's what Get by Index is for - For Each is for the "do this to all of them" case.

Installing

Ships in Kinburg-Nodes: ComfyUI Manager → search "Kinburg-Nodes", or:

cd ComfyUI/custom_nodes
git clone https://github.com/Kinburg/Kinburg-Nodes
# restart ComfyUI

No extra dependencies - it's pure ComfyUI graph semantics.

Gotchas

The loop iterates to the shortest connected input, so if one value_* has 5 items and another has 7, you get 5 iterations and the extra two silently vanish. Keep equal lengths. And remember the map shape: no state is carried between iterations. If you need an iteration to know what the previous one produced - a running accumulator, a feedback pass - that's the Repeat (Open/Close) family's job, which uses graph expansion and state-carrying wildcard slots instead. For Each is for embarrassingly parallel per-item work, which is most of what you'll want it for.

CategoryKinburg-Nodes/flow/loops

Inputs (20)

NameTypeDefaultDescription
value_0opt*
value_1opt*
value_2opt*
value_3opt*
value_4opt*
value_5opt*
value_6opt*
value_7opt*
value_8opt*
value_9opt*
value_10opt*
value_11opt*
value_12opt*
value_13opt*
value_14opt*
value_15opt*
value_16opt*
value_17opt*
value_18opt*
value_19opt*

Outputs (23)

NameTypeDescription
flowKINBURG_LOOP_FLOW
indexINT
totalINT
element_0*
element_1*
element_2*
element_3*
element_4*
element_5*
element_6*
element_7*
element_8*
element_9*
element_10*
element_11*
element_12*
element_13*
element_14*
element_15*
element_16*
element_17*
element_18*
element_19*