π Bulk Prompt Loader (CSV / Sheets)
Batch-run a whole CSV of prompts by pressing Queue once
- positive
- negative
- filename_tag
- current_row
- total_rows
- is_last_row
You have two hundred prompts in a spreadsheet, and you are not going to paste them into a CLIP Text Encode one at a time. The Bulk Prompt Loader is the node that makes "queue once, walk away" real: each run of your workflow gets one row from your list, and when that run finishes the node queues the next one itself. Press Queue, go make coffee, come back to a folder full of images. It's the centerpiece of the sifatrads/comfyui-bulk-prompt pack, and everything else in the pack exists to feed it or reset it.
What it actually does
It reads rows from one of three sources - a CSV file on disk, a published Google Sheets URL, or text you paste into the node - and spits out one row's worth of strings per execution. Wire positive into your CLIP Text Encode (positive), negative into the negative one, and every generation uses that row. The load happens fresh each run, so you can edit the CSV while ComfyUI is still open and the next row sees the change.
The mechanism is worth knowing before you trust it: the auto-loop is driven from the browser, not the backend. The node's JS calls a /bulkprompt/loader/continue endpoint then re-queues the prompt after each run finishes. That's why the README's warning matters - keep the ComfyUI tab open and awake, or the batch silently stops. The row position lives in manual_index, which is the single source of truth: the front-end writes the current row back into it after every step, and it's persisted in a state.json inside the node folder, so an interrupted batch resumes where it left off. The node also returns float("nan") from IS_CHANGED (the always-rerun trick, if you've seen the phrase) so ComfyUI's cache never skips it.
The inputs that matter
There are a lot of widgets, but a beginner sets four:
- source -
CSV File,Google Sheets URL, orPaste Text. Everything below depends on this. - csv_file - a dropdown of the
.csvfiles sitting inComfyUI/custom_nodes/ComfyUI-BulkPrompt/csv_files/. Drop your file there, refresh, pick it. - auto_loop -
enabled(default) means the node re-queues itself until every row is done. This is the entire point of the node; leave it on. - reset_on_start -
yesstarts every fresh Queue press at row 0. Set it tonoand the batch continues from wherevermanual_indexleft off.
The column names are flexible: positive_column, negative_column, and tag_column default to positive / negative / filename_tag, but set them to match whatever your header row says. loop_forever (yes/no) wraps back to row 0 after the last row instead of stopping. manual_index is the live counter - you can scrub it by hand to jump to a specific row, which is handy for testing one prompt before committing to the whole batch. pasted_data is only used when source is Paste Text, and it auto-detects: one prompt per line, a comma-separated line, or full CSV with headers.
Outputs and what to do with them
positive/negative- the prompt strings. Feed them to your CLIP Text Encode nodes.filename_tag- a short per-row label. Concatenate it into your Image Saver's filename so each image is named after its prompt row. Do this from day one; retroactively matching 200 images to prompts is misery.current_row,total_rows,is_last_row- integers and a boolean you can use for downstream logic, like a node that only runs on the final image.
Installing it
This is the nice part: the core loader has zero Python dependencies - it's standard-library csv, urllib, and json only, so there's nothing to pip install. Via ComfyUI Manager, search for "bulk prompt". Or:
cd ComfyUI/custom_nodes
git clone https://github.com/sifatrads/comfyui-bulk-prompt.git
Then restart ComfyUI. The nodes land under BulkPrompt in the menu.
Where people get burned
- The batch stops mid-way with no error. The auto-loop is browser-driven, so any tab refresh, sleep, or close kills it. Keep the tab open. The counter is saved, so just re-queue to continue.
- "No data rows found" - your CSV is empty, or you pointed the file dropdown at the placeholder
(no csv files found)entry. Check thecsv_filesfolder. - Row counter weirdness after editing pasted text - changing the paste resets the run to row 0 by design (it keys state on a hash of the text).
- One stale README line says to set
reset_counter β yeson the loader. That input doesn't exist in the current node - the loader-side control isreset_on_start, and there's a dedicated Bulk Prompt Reset Counter node for clearing everything.
Honest caveat: this pack is brand new (basically zero install base as of this writing), so expect rough edges. The pattern is proven - it's the same niche as the older CSV-to-Prompt node, just with a live counter and a browser-driven loop instead of the seed/batch-count trick.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| source | COMBO | 3 options: CSV File, Google Sheets URL, Paste Text | |
| csv_file | COMBO | 1 options: example_prompts.csv | |
| sheets_url | STRING | https://docs.google.com/spreadsheets/d/.../pub?output=csv | β |
| positive_column | STRING | positive | β |
| negative_column | STRING | negative | β |
| tag_column | STRING | filename_tag | β |
| auto_loop | COMBO | enabled | Auto-queue the next prompt until all rows are done |
| loop_forever | COMBO | no | After the last row, loop back to row 0 |
| reset_on_start | COMBO | yes | yes = each Queue press starts the batch at row 0. no = start at manual_index (which keeps counting up as the loop runs). |
| manual_index | INT | 00β99999 | Live row counter (0-based: 0 = first row). It auto-advances as the loop runs; edit it to jump. reset_on_start=yes starts each Queue at 0; reset_on_start=no starts at this value. |
| pasted_data | STRING | Used when source = Paste Text. One prompt per line, a comma-separated list on one line, or full CSV (header row + rows). |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| positive | STRING | β |
| negative | STRING | β |
| filename_tag | STRING | β |
| current_row | INT | β |
| total_rows | INT | β |
| is_last_row | BOOLEAN | β |