For Loop Start (VantageV2)
Run a chunk of your graph N times
- initial_value
- flow
- index
- value
ComfyUI's execution model is a DAG - no back edges, no loops. This pair of nodes is the sanctioned workaround: it doesn't loop inside a node, it asks the engine to expand your subgraph into copies and run them one after another.
First, should you be here?
Honestly? Most people shouldn't. Searching the reddit corpus for "while loop" turns up sixteen threads over two years, and half of those are people asking whether ComfyUI can loop at all. Batching, prompt queues and AnimateDiff-style frame batching cover the common cases. What a loop buys you is something different: a value carried across iterations, updated by the body each pass. If you need "start at 0, add 1, do it three times, hand me 3", that's this. If you need 20 images from 20 prompts, use the queue.
What Start gives you
Two inputs. total is the iteration count, default 1, and zero is legal. initial_value is an optional wildcard - whatever the body should receive on the first pass.
Three outputs. flow is the pseudo-socket you wire to the matching For Loop End and nowhere else. index is the current zero-based iteration. value is the carried value: initial_value on iteration 0, then whatever the body produced last time.
index is the one you'll use for anything positional - a per-iteration seed (seed + index), a prompt pulled from a list, a filename suffix. value is the one that makes it a loop rather than a countdown.
How the mechanism actually works
It's graph expansion, not a Python for. The pack's loops.py collects the nodes on the path from Start to End, copies them into a fresh graph with a GraphBuilder, swaps Start for a hidden VantageLoopIteration node, and hands the engine that expanded graph. Each iteration is a real execution of your body with index bumped. When index + 1 reaches total, End returns the carried value and the loop is done.
Two consequences you can't argue with:
- Only the dependency path from Start to End repeats. A Preview Image or Save Image sitting in the body but not upstream of End's
valueinput will not run per iteration. This is the single biggest "my loop does nothing" cause. If you need a side effect each pass, it has to feed End. - Loops nest by wiring. Put an inner Start inside the body, feed the outer carried value into the inner Start's
initial_value, and the expansion handles it. Use matching Start/End types - a For Start can't drive a While End.
The body subscribes to ComfyUI's normal caching too, so a body whose inputs don't change can be reused between passes; do not assume every iteration re-samples if nothing downstream forces it.
Wiring it, concretely
flow → For Loop End's flow. Whatever your body computes as the updated value → For Loop End's value. Then use End's value output as the loop's result. Start's index can go anywhere in the body that wants it - that's not part of the loop closure, it's just data.
Canonical smoke test: initial_value = 0, body = an integer add of 1, total = 3. Indices 0, 1, 2; End outputs 3.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/vantagewithai/Vantage-NodesV2.git
Restart ComfyUI, hard-refresh, then find Vantage/Loops in the Add Node menu. ComfyUI Manager should also list the pack as Vantage-NodesV2, though the git clone is what the README documents.
No pip step - no requirements file, no declared dependencies; everything comes from ComfyUI. But this node has a real compatibility floor: it needs ComfyUI's graph expansion API and lazy input evaluation, both of which live in comfy_execution. A ComfyUI from before those landed will import the pack and then fail at execution time with an expansion error, which reads like a pack bug and isn't.
Troubleshooting
ValueError: Loop End must be connected to its matching Loop Start means the closure isn't what you think it is - usually End isn't actually downstream of Start, or you've crossed a For Start into a While End.
Loop runs once and stops: check total. It defaults to 1, and 0 skips the body entirely and returns initial_value unchanged - which is correct behaviour and looks like failure.
Body seemingly doesn't run: check what End's value actually depends on. Anything outside that path is treated as a one-off.
And if a pack update changes the node's inputs, create a fresh instance - saved nodes keep their original schema.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| total | INT | 10–2147483647 | — |
| initial_valueopt | * | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| flow | VANTAGE_LOOP | — |
| index | INT | — |
| value | * | — |