⏹️ Loop Close
The Other Half of ComfyUI's Only For-Loop
- LOOP
- data
- aux
- aux2
- aux3
- aux4
- aux5
- FINISHED?
- data
- aux
- aux2
- aux3
- aux4
- aux5
You don't use LoopClose alone - it's the closing brace of the only real for-loop ComfyUI has. Its partner LoopOpen starts the loop; LoopClose sits at the end of the block you want repeated, and decides whether to run another iteration or call it done. Most of the interesting machinery actually lives in this node.
What it does
Three jobs, all visible in its inputs and outputs:
1. It terminates the loop. The LOOP input (required) connects to LoopOpen's LOOP output and carries the loop's state - current index, start, step, end, finished flag. LoopClose reads finished from that dict. If it's done, the loop stops and the final data comes out.
2. It holds the per-iteration state. data, aux, aux2–aux5 are optional inputs. Whatever you feed in here at the end of an iteration gets handed back to LoopOpen's matching data/aux outputs as the starting values for the next iteration. That round-trip is the entire mechanism for accumulating anything across iterations - think of it as the loop variable that survives each pass.
3. It runs the next iteration. If the loop isn't finished, LoopClose does the heavy lifting: it asks ComfyUI's Execution Model Inversion machinery (via the GraphBuilder) to clone every node between LoopOpen and LoopClose, wire the current data into the copies, and re-run them. Each iteration is literally a fresh set of node copies. This is the "proof of concept" part the author flags - it's powerful, and occasionally buggy, which is why you want a current ComfyUI and why the README says to report issues.
The outputs are the payoff:
- FINISHED? - boolean,
Trueonce the loop is done. This is your signal to route execution onward (or to loop-chain into another stage). - data / aux / aux2–aux5 - the final values after the last iteration. This is how the loop hands its result back to the rest of the workflow.
There's also a condition string input (default "True") so LoopClose can early-exit if a while-style condition stops holding - combined with LoopOpen's own condition you can build "for-range AND while-condition, whichever ends first."
Common traps
The classic mistake is forgetting the state round-trip: you wire a value into LoopOpen's data but never feed the processed result back into LoopClose's data. The loop still runs, but every iteration sees the same starting value, so nothing accumulates and you get N identical results. If your loop isn't progressing, trace the data/aux loop first.
Second, memory. Every iteration's node copies and outputs stay cached, so a long loop can balloon RAM. That's expected behavior for this execution model - drop a GarbageCollector node inside the loop body and batch long runs rather than expecting a 1000-iteration loop to be free. There's real-world confirmation of this: a popular 1000-image img2img animation built on these loop nodes had to be split into batches because ComfyUI kept every iteration in memory.
Third, version. If LoopClose refuses to run and complains about being unable to create the loop system, your ComfyUI is too old - the Execution Model Inversion backend is a relatively recent core feature.
Install
LoopClose ships in VykosX/ControlFlowUtils:
# ComfyUI Manager → Install Custom Nodes → search "ControlFlowUtils"
# or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/VykosX/ControlFlowUtils
Restart, find it under 🐺 VykosX-ControlFlowUtils, and start from one of the repo's sample loop workflows - the screenshots and demos teach the data round-trip faster than reading about it.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| LOOP | * | Connect to the LOOP output of a [Loop Open] node to establish a Loop | |
| condition | STRING | True | The loop will be executed only if the specified condition evaluates to True |
| dataopt | * | Any data you wish to iterate on in the loop | |
| auxopt | * | Any auxilliary data you wish to iterate on in the loop | |
| aux2opt | * | Any auxilliary data you wish to iterate on in the loop | |
| aux3opt | * | Any auxilliary data you wish to iterate on in the loop | |
| aux4opt | * | Any auxilliary data you wish to iterate on in the loop | |
| aux5opt | * | Any auxilliary data you wish to iterate on in the loop |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| FINISHED? | BOOLEAN | This output will return True when the Loop is done executing |
| data | * | Final values for any Data that has been processed by the Loop |
| aux | * | Final values for any Data that has been processed by the Loop |
| aux2 | * | Final values for any Data that has been processed by the Loop |
| aux3 | * | Final values for any Data that has been processed by the Loop |
| aux4 | * | Final values for any Data that has been processed by the Loop |
| aux5 | * | Final values for any Data that has been processed by the Loop |