Batch Image Loader Start
A for-loop for your folder, hiding in ComfyUI
- values
- loop
- image
- filename
- meta_bundle
- value1
- value2
- value3
- value4
- value5
- value6
- value7
- value8
- value9
- value10
- value11
- value12
- value13
- value14
- value15
- value16
ComfyUI has no loop node. It has output lists, and it has people building counters and external scripts and, in one thread I read, quietly giving up on looping over a folder at all ("indeed are other looping tools definitely more complicated..."). The Nifty pair is a proper answer to that: a folder in, one image per iteration, everything between the two nodes running again each time.
This article is the Start half. The End node is where the actual iteration lives - read that one too, because half of what's confusing about this node is really about its partner.
What it's for
Batch work that isn't a batch tensor. You have 200 upscales to run through one workflow. Or 40 frames to send through an edit model and save back out. Or you want to drop images into a folder and have each one pick up a prompt from its filename. The thing ComfyUI gives you natively - an IMAGE batch - means every frame travels together through the same graph and comes out as one lump. Sometimes that's exactly wrong, and you need them to arrive one at a time, with file-level bookkeeping in between.
That's the niche: per-file processing with per-file decisions, plus rename/move/delete afterwards.
How it works
Start walks the directory once, sorts the file list, and emits a loop token carrying the folder, the sorted list and the current index. It also emits the image, its relative path, its embedded metadata bundle, and up to sixteen "value" slots.
Then things get interesting. The End node is an output node, and each time it finishes an iteration it rebuilds the section of graph between Start and End as a new iteration with the index incremented, and hands that back to the executor. So the folder drains inside a single queue run, as a growing prompt graph rather than a Python loop. Practical upshot: each iteration is another copy of everything between the two nodes, so a 500-file folder is a heavy graph - use start_index and limit to work in slices rather than discovering that the hard way on your first run.
Sorting is smarter than it looks. orderby: name uses a natural key, so img2.png comes before img10.png - an ordering people fight for years with lexical sorts. Other criteria are date modified, date created, size and type.
Inputs and outputs
The ones you'll actually set:
directory- absolute, or relative to the ComfyUI root. The default isoutput, i.e. the folder ComfyUI just saved into. Handy for a two-pass workflow: save the first pass, then loop over it.limit- how many images to process.-1is all, and0is none (which does nothing at all, quietly).start_index- skip the first N of the sorted list. Combined withlimit, this is your windowing.recursive- walk subfolders too, with relative paths preserved in thefilenameoutput.
Outputs: the loop token (wire it to Batch Image Loader End - nothing runs otherwise), image, filename (path relative to directory, subfolders included), meta_bundle (the PNG text chunks embedded in that file, if any), and value1…value16, which are the state-carrying slots you pass on to the same slot on End.
One honest limit: the loader scans images - png, jpg/jpeg, jfif, jpe/pjp/pjpeg, webp. Point it at a folder of AVIFs or MP4s and it finds nothing, and does so without an error.
Installing it
ComfyUI Manager → search Nifty Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Stibo/comfyui-nifty-nodes
Restart ComfyUI. Manager pulls the pack's declared dependencies (color-matcher, imageio-ffmpeg); this node needs none of them. The pack is written on ComfyUI's newer V3 node API - no NODE_CLASS_MAPPINGS in the source is normal, not a sign of breakage. The author tested against frontend 1.39 and hasn't tested Nodes 2.0; loop/expansion nodes are the least forgiving thing to be untested on, so keep the legacy canvas around if this is load-bearing for you.
Under the hood, Start declares itself as always-dirty (fingerprint_inputs returning NaN), which is the standard idiom for a node that must re-run rather than be served from cache.
Where people get burned
- Files can be destroyed. Not by this node - Start only reads - but its partner moves and deletes. Run a first pass with
file_action: noneon a copy of the folder and confirm the loop is doing what you think before handing it anything irreplaceable. - It reaches outside
output. Relative paths resolve from the ComfyUI root and absolute paths are accepted, which is convenient and also means a typo'd path is a real path somewhere. - Values carry state, and only if you close the circle. Slot
value1on Start is the initial value; from the second iteration on it's whatever you fed back into End'svalue1. Wire one side and not the other and your counter never counts. - Empty folder, no error. If the directory doesn't exist you get a
FileNotFoundError; if it exists but holds no images, you get blocked outputs and a queue that appears to do nothing. Check the folder contents first.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| directory | STRING | output | Absolute path, or relative to the ComfyUI root (e.g. 'output'). |
| limit | INT | -1-1–2147483647 | Number of images to process. -1 = all, 0 = none. |
| start_index | INT | 00–2147483647 | Number of images to skip at the start of the sorted list. |
| orderby | COMBO | name | Sort criterion. 'name' uses natural order (1, 2, 10, 100). |
| order | COMBO | ascending | 2 options: ascending, descending |
| recursive | BOOLEAN | false | Also read images from subdirectories. |
| valuesopt | COMFY_AUTOGROW_V3 | — |
Outputs (20)
| Name | Type | Description |
|---|---|---|
| loop | NIFTY_BATCH_LOOP | Connect to Batch Image Loader End. |
| image | IMAGE | — |
| filename | STRING | Path relative to the directory, including subfolders. |
| meta_bundle | BUNDLE | — |
| value1 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value2 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value3 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value4 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value5 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value6 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value7 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value8 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value9 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value10 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value11 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value12 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value13 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value14 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value15 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |
| value16 | * | Value of the current iteration. Pass it on to the same slot of Batch Image Loader End. |