ComfyUI Node

For Loop Start

Stop copy-pasting that group eight times

By wenchengxiang·Created 2 months ago·Updated 9 days ago· 3
For Loop Start
  • initial_value1
  • initial_value2
  • initial_value3
  • initial_value4
  • initial_value5
  • initial_value6
  • initial_value7
  • initial_value8
  • initial_value9
  • initial_value10
  • initial_value11
  • initial_value12
  • initial_value13
  • initial_value14
  • initial_value15
  • initial_value16
  • initial_value17
  • initial_value18
  • initial_value19
  • flow
  • index
  • value1
  • value2
  • value3
  • value4
  • value5
  • value6
  • value7
  • value8
  • value9
  • value10
  • value11
  • value12
  • value13
  • value14
  • value15
  • value16
  • value17
  • value18
  • value19
◄total1►

What it actually is

ComfyUI has no loop construct. Its execution model is a directed graph evaluated once: you build a chain, you hit Queue, the chain runs. If you want the same block to run eight times with a different number each time, the historical answer is to duplicate the block eight times, or wrap it in a group and paste it, or find a pack that fakes it.

For Loop Start is the entry half of that fake. It's one of a pair - Start and For Loop End bracket a region of your graph and the pair turns that region into a counted loop, so the nodes between them run total times without being duplicated by hand. That's the whole reason to reach for it. Not speed, not quality - ergonomics and the ability to change "8" to "24" in one widget.

It comes from ComfyUI-Practical-Tools, a grab-bag utility pack whose README is one sentence long. The machinery is modelled on ComfyUI-Easy-Use's loop nodes - the source caps carried values at 20 "consistent with EasyUse" - but packaged standalone, so you don't install all of Easy-Use to get a for loop. Community signal on these nodes is near-silent; the plumbing layer is the part nobody writes about (comfyui-node-plumbing.md covers switches and wildcards, nothing on loops).

How the loop really works

For Loop Start doesn't loop anything by itself. It uses ComfyUI's dynamic prompt expansion (GraphBuilder) to rewrite the graph while it runs.

When it executes, For Loop Start emits a WhileLoopStart node with condition=total and initial_value0=0, and hands out flow as a stub. For Loop End then does the actual work: each round it reads total back off this node, computes the next index, and copies the entire region between the two nodes into a fresh pass, feeding the carried values back into the top of the copy. Repeat until the counter hits total.

The practical consequence: the index you read from For Loop Start is not a constant - inside the body it's the current round's number, starting at 0. total=8 gives you index 0,1,2,3,4,5,6,7.

The sockets that matter

  • total (INT, default 1, min 1, max 100000) - the iteration count. The only widget you normally touch.
  • flow (output) → wire to For Loop End's flow. This is the loop bracket; it carries the link itself, not data.
  • index (INT out, 0-based) → filenames, seeds (index * 1000), a LoRA strength ramp, a list index. This is why you're here.
  • value1 … value19 (wildcard, in and out) - 19 slots of loop state. On Start they are the current values of that slot; you hand the updated version back through For Loop End's matching initial_value1…19. Anything works: latents, images, strings, a batch tensor.

So the shape is: Start → (your body: sampler, accumulate, whatever) → End, with the body's outputs landing on End's initial_value sockets and Start's valueN sockets feeding the next round.

Install

ComfyUI Manager, search ComfyUI-Practical-Tools (it's on the Comfy Registry under publisher wcx, current version 2.0.11), or:

cd ComfyUI/custom_nodes
git clone https://github.com/wenchengxiang/ComfyUI-Practical-Tools
# restart ComfyUI

The pack's requirements.txt (onnxruntime, nvidia-vfx, openai>=1.0.0) is for its other nodes - tagger, RTX super-resolution, ModelScope API. Loops need none of it, and nothing downloads a model. Useful detail: the pack's loader imports each Python file in isolation inside a try/except, so if nvidia-vfx won't install on your box you get a [WCX Nodes Error] console line and every other node still registers.

Where people get burned

A node in the box that isn't wired into the loop doesn't loop. The End builds its copy list by walking backwards from its own inputs. A stray node sitting between Start and End that doesn't (transitively) feed End runs exactly once, silently. If half your loop "isn't repeating", this is why.

The carried value only survives if it goes through End. Start's valueN is the current state each round, not a memory. Leave the corresponding End socket unwired and that slot resets to nothing on round two.

Mute the Start and the loop quietly becomes a single pass. For Loop End checks that the node feeding flow is a For Loop Start; if it isn't (because you bypassed it, or the wire came from somewhere else), it falls back to passing the values straight through and ends. No error, one iteration, confusing afternoon.

Wildcards don't warn you. These sockets are the * type, so you can hand round one a tensor and round two a string, and nothing stops you - you'll just get whatever the node downstream makes of a mismatched list.

Total cost is total × body. Everything inside the loop re-executes each round and ComfyUI keeps those intermediates alive, so a 30-round loop with a sampler in the middle is 30 sampler runs and a lot of RAM. That's not a bug, but it's the thing to remember before you set total to 200 and go make coffee.

CategoryPractical-Tools/Logic

Inputs (20)

NameTypeDefaultDescription
totalINT11–100000—
initial_value1opt*—
initial_value2opt*—
initial_value3opt*—
initial_value4opt*—
initial_value5opt*—
initial_value6opt*—
initial_value7opt*—
initial_value8opt*—
initial_value9opt*—
initial_value10opt*—
initial_value11opt*—
initial_value12opt*—
initial_value13opt*—
initial_value14opt*—
initial_value15opt*—
initial_value16opt*—
initial_value17opt*—
initial_value18opt*—
initial_value19opt*—

Outputs (21)

NameTypeDescription
flowWFLOW_CONTROL—
indexINT—
value1*—
value2*—
value3*—
value4*—
value5*—
value6*—
value7*—
value8*—
value9*—
value10*—
value11*—
value12*—
value13*—
value14*—
value15*—
value16*—
value17*—
value18*—
value19*—