ForEach (misc)
Run a chunk of graph once per value, without writing Python
- combined
- *
Loops are ComfyUI's awkward age. Core ComfyUI has no built-in "for each item in a list, run this chain" node - that's exactly the gap ForEach (misc) fills. Feed it a combined bundle from Combine Primitives (misc), and it unpacks the values, then pushes each one through a * output in turn so everything downstream runs once per element. Pair it with End ForEach (misc) to collect the per-iteration results back into a bundle, and you've got a real loop drawn as a graph.
The standard use is batch processing a handful of related runs without copy-pasting a node chain N times: pack several prompts into one bundle, run each through the same sampler-and-decode chain, and End ForEach gathers the images. Add a value to the Combine and the loop grows a step - no rewiring.
How it works. The mechanism is ComfyUI's native list execution. ForEach returns its list of values and declares OUTPUT_IS_LIST, which tells the engine "I'm handing you a list, run my downstream once per item." That's the whole trick - no hidden iteration node, no custom frontend loop; it rides a feature the backend already ships. Any node you hang off the * output - a sampler, a text encode, a save - executes one time per element, receiving each value in turn.
The input and output. One input: combined (PRIMITIVES). One output: *, which is deliberately kept as a wildcard even after you connect it, so the same socket can carry whatever the current element happens to be. That "label and type stay * even when connected" behavior is a small choice that matters - it means you can wire one loop body and have it carry a prompt in one workflow and an integer in another.
Install. From ComfyUI/custom_nodes:
git clone https://github.com/wraith-executioner-year-2/comfyui-misc/
Restart ComfyUI; the node lives in the misc category. No models, no dependencies beyond ComfyUI itself.
Where people get burned: loops multiply work - N elements means N sampler executions, so a 4-item loop over a heavy sampler is 4x the time, and it's easy to forget you built one. Also, list execution with a chain that itself has branching or a node that isn't list-friendly can produce confusing partial runs; keep the loop body linear. And everything between ForEach and its matching End ForEach reruns each iteration, so don't put an expensive loader (or anything that shouldn't run N times) inside the loop body - load once outside it. It's a genuinely useful utility, just respect what a for-loop implies about runtime.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| combined | PRIMITIVES | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| * | * | — |