ComfyUI Extension: Workflow Iterator

Authored by jason-n-tran

Created

Updated

3 stars

Run ComfyUI workflows without the setup

No installs, no CUDA version roulette, no GPU sitting idle on your bill. Bring a workflow and run it in the browser.

A/B testing and batch parameter comparison nodes for ComfyUI

README

ComfyUI Workflow Iterator

<!-- LOGO placeholder -->

Live Demo Live Demo License: MIT Python 3.9+ ComfyUI Version

Systematic A/B testing and parameter sweep tooling for ComfyUI workflows. Define ranges or lists of values for any node widget — CFG scale, sampler, steps, prompts, seeds — and the extension automatically queues every combination, then assembles a labeled comparison grid when the batch is complete. Stop tweaking sliders one at a time and start running controlled experiments.


<!-- Best screenshot: a side-by-side showing (1) the ComfyUI canvas with a Workflow Iterator node, two WIParameter nodes, and a WIGridCompositor node wired up, and (2) the resulting labeled comparison grid image in the output panel. -->

Workflow Iterator in action


Table of Contents


About The Project

Motivation

ComfyUI's default workflow executes one prompt at a time. Finding optimal generation settings — the right CFG scale, the best sampler, the most effective prompt — requires manually adjusting widgets, re-queuing, and visually comparing results held only in memory. This process is slow, error-prone, and produces no structured record of what was tested.

Workflow Iterator treats parameter exploration as a first-class workflow operation. You declare what to vary, how many combinations to generate, and where to save results — then walk away while the batch runs.

Key Features

  • Five typed parameter nodes — dedicated nodes for INT, FLOAT, STRING, COMBO, and SEED types, each with its own parsing and validation logic.
  • Expressive value syntax — define ranges with step (10-30, 5), comma-separated lists (euler, dpm_2, ddim), random seeds (random:5), or sequential seeds (increment:100:5).
  • Two combination strategiesmatrix mode generates the full Cartesian product of all parameters; linear mode zips them index-by-index with cycling for curated, efficient runs.
  • Automatic labeled comparison grids — the WIGridCompositor node assembles a 2D grid (for two-parameter matrix sweeps) or a linear strip, with axis labels derived directly from the parameter values tested.
  • PNG metadata embedding — every saved image carries a structured JSON payload and an A1111-compatible parameter string describing the exact combination that produced it.
  • Wildcard expansion — string parameters support __wildcard_name__ file references and {option1|option2} inline syntax, expanding before combination generation.
  • Live progress overlay — a JavaScript frontend extension polls the active batch status and renders a progress indicator directly on the WorkflowIterator node in the canvas.
  • Batch cancellation API — cancel a running batch via HTTP without restarting ComfyUI.

Built With

Python JavaScript Pillow pytest

| Component | Technology | |---|---| | Backend | Python 3.9+ | | Image processing | Pillow ≥ 9.0.0, NumPy | | Async HTTP routes | aiohttp (via ComfyUI's embedded PromptServer) | | Frontend progress UI | Vanilla JavaScript (ComfyUI extension API) | | Packaging | pyproject.toml (PEP 517) | | Testing | pytest |


Getting Started

Prerequisites

  • ComfyUI — any recent version. (Installation guide)
  • Python 3.9 or higher — bundled with most ComfyUI installations.
  • Git — for cloning the repository.

Installation

Option A — ComfyUI Manager (recommended)

If you have ComfyUI Manager installed, search for "Workflow Iterator" in the Custom Nodes panel and click Install. Restart ComfyUI when prompted.

Option B — Manual install

  1. Clone the repository into your ComfyUI custom_nodes directory:
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/YOUR_USERNAME/comfyui-workflow-iterator
  1. Install the Python dependency:
# Using ComfyUI's embedded Python (recommended)
/path/to/ComfyUI/python_embeded/python -m pip install Pillow>=9.0.0

# Or, if using a system/venv Python
pip install Pillow>=9.0.0
  1. Restart ComfyUI. The Workflow Iterator nodes will appear in the node browser under the Workflow Iterator category.

Usage

Building a Parameter Sweep Workflow

A complete iteration workflow requires four elements wired together on the canvas:

[WIParameter nodes] ──param_stack──► [WorkflowIterator] ──iteration_meta──► [WIGridCompositor]
                                             │
                                      targets any node's
                                      widget at runtime
                                      (e.g., KSampler.cfg)

Step-by-step:

  1. Add a WI Workflow Iterator node from the node browser (Workflow Iterator category). Set mode to matrix or linear and give the batch a name.

  2. Add one or more WI Parameter nodes (Int, Float, String, Combo, or Seed). Chain them by connecting each node's param_stack output to the next node's param_stack_in input. Connect the final node's param_stack output to the WorkflowIterator node's param_stack input.

  3. Configure each parameter node:

    • parameter_name — a display label (used in grid axis labels and filenames).
    • values — the values to sweep (see syntax reference below).
    • target_node_title — the title of the node whose widget you want to control (e.g., KSampler).
    • target_widget_name — the exact widget name (e.g., cfg, steps, sampler_name).
  4. Add a WI Grid Compositor node. Connect iteration_meta from the WorkflowIterator. This node collects each iteration's output and assembles the grid on completion.

  5. Queue the workflow. The extension intercepts the submission, generates all combinations, and queues them automatically.


Parameter Value Syntax

| Type | Format | Example Input | Parsed Result | |---|---|---|---| | INT | Range with step | 10-30, 5 | [10, 15, 20, 25, 30] | | INT | Comma list | 10, 20, 30 | [10, 20, 30] | | FLOAT | Range with step | 0.5-1.5, 0.25 | [0.5, 0.75, 1.0, 1.25, 1.5] | | FLOAT | Comma list | 5.0, 7.5, 10.0 | [5.0, 7.5, 10.0] | | STRING | Newline-separated | a cat\na dog | ["a cat", "a dog"] | | COMBO | Comma list | euler, dpm_2, ddim | ["euler", "dpm_2", "ddim"] | | SEED | Random count | random:5 | 5 random integers | | SEED | Sequential | increment:100:4 | [100, 101, 102, 103] | | SEED | Explicit list | 42, 1337, 9999 | [42, 1337, 9999] |

Wildcard expansion (STRING type only):

__subjects__           # loads every line from wildcards/subjects.txt
{cat|dog|bird}         # inline random selection
a photo of __subjects__ in {summer|winter}

Wildcards are expanded before combination generation, so each resolved string becomes a separate combination value.


Combination Modes

| Mode | Behaviour | Best for | |---|---|---| | matrix | Full Cartesian product of all parameters | Exhaustive exploration — 3 params × 10 values = 1,000 renders | | linear | Index-by-index pairing, shorter lists cycle | Curated comparisons — always equals the longest list length |

Example — matrix mode with 2 parameters:

| | euler | dpm_2 | |---|---|---| | cfg=5 | ✓ | ✓ | | cfg=7 | ✓ | ✓ | | cfg=9 | ✓ | ✓ |

6 renders, assembled into a 3×2 labeled grid automatically.

Example — linear mode with the same parameters:

| Iteration | sampler | cfg | |---|---|---| | 0 | euler | 5 | | 1 | dpm_2 | 7 | | 2 | euler (cycling) | 9 |

3 renders. Shorter list cycles to fill.


HTTP Status API

The extension registers REST endpoints on ComfyUI's built-in server:

# List all active batches
GET /wi/active_batches

# Get progress for a specific batch
GET /wi/batch_status/{batch_id}

# Cancel a running batch
POST /wi/cancel_batch/{batch_id}

Example response from /wi/active_batches:

{
  "sampler_test_a3f9c12b": {
    "total": 6,
    "completed": 2,
    "name": "sampler_test",
    "mode": "matrix",
    "cancelled": false,
    "age_seconds": 14
  }
}

Node Reference

WI Workflow Iterator

The main control node. Detects WIParameter nodes connected via param_stack, generates combinations, and outputs iteration metadata for downstream nodes.

| Input | Type | Description | |---|---|---| | mode | COMBO | matrix (cartesian) or linear (zip with cycling) | | batch_name | STRING | Prefix for output filenames and batch ID | | enabled | BOOLEAN | Disable to run the workflow once without iterating | | param_stack | WI_PARAM_STACK | Connect from the last WIParameter node in the chain |

| Output | Type | Description | |---|---|---| | current_index | INT | Index of this execution within the batch (0-based) | | total_count | INT | Total number of iterations in this batch | | batch_name | STRING | Pass-through of the batch name | | iteration_meta | WI_ITERATION_META | Structured metadata dict for downstream nodes |


WI Parameter (Int / Float / String / Combo / Seed)

Defines one parameter to sweep. Chain multiple nodes together via param_stack_inparam_stack.

| Input | Type | Description | |---|---|---| | parameter_name | STRING | Display label — appears in grid axis labels | | values | STRING | Value list or range (see syntax table above) | | target_node_title | STRING | Canvas title of the node to control | | target_widget_name | STRING | Widget name on the target node | | enabled | BOOLEAN | Disable to exclude this parameter without disconnecting it | | param_stack_in | WI_PARAM_STACK | (Optional) Connect from the previous parameter node |


WI Grid Compositor

Collects each iteration's output image, then assembles and saves a labeled comparison grid on the final iteration.

| Input | Type | Description | |---|---|---| | images | IMAGE | Connect to the image output of your generation pipeline | | cell_width / cell_height | INT | Size of each image cell in the grid (px) | | padding | INT | Pixel gap between cells | | label_font_size | INT | Font size for axis labels | | x_param_name / y_param_name | STRING | Override which parameter appears on each axis | | save_grid | BOOLEAN | Save the assembled grid to disk | | output_dir | STRING | Subdirectory under ComfyUI's output folder | | iteration_meta | WI_ITERATION_META | Connect from the WorkflowIterator node |


WI Save Image

A drop-in replacement for ComfyUI's built-in Save Image node that embeds iteration metadata into the PNG and uses parameterized filenames.


Project Structure

comfyui-workflow-iterator/
├── __init__.py               # Extension entry point — node registration,
│                             # onprompt hook, HTTP route registration
├── pyproject.toml            # Package metadata and dependencies
│
├── nodes/                    # ComfyUI node class definitions
│   ├── workflow_iterator.py  # WorkflowIteratorNode
│   ├── parameter_input.py    # WIParameterInt/Float/String/Combo/Seed
│   ├── save_image.py         # WISaveImage
│   └── grid_compositor.py    # WIGridCompositor
│
├── core/                     # Business logic (no ComfyUI dependencies)
│   ├── parameter_parser.py   # Type-aware value string parser
│   ├── combination_engine.py # Cartesian and linear_zip generators
│   ├── iteration_state.py    # Thread-safe singleton batch manager
│   ├── grid_builder.py       # PIL-based grid assembly
│   ├── metadata.py           # PNG metadata construction and embedding
│   └── wildcard.py           # Wildcard file and inline expansion
│
├── web/
│   └── workflow_iterator.js  # Frontend: progress overlay, node browser
│                             # widget picker, value preview counter
│
└── tests/
    ├── test_parameter_parser.py
    ├── test_combination_engine.py
    ├── test_grid_builder.py
    ├── test_metadata.py
    └── test_wildcard.py

The core/ directory has no dependencies on ComfyUI internals and can be imported and tested with a plain Python interpreter.


Running Tests

The test suite uses pytest and requires no running ComfyUI instance.

# Install dev dependencies
pip install pytest Pillow

# Run all tests from the repository root
pytest tests/ -v

# Run a specific module
pytest tests/test_parameter_parser.py -v

# Run with coverage (requires pytest-cov)
pip install pytest-cov
pytest tests/ --cov=core --cov-report=term-missing

All tests live in tests/ and are organised per core module. The core/ package is importable standalone because __init__.py wraps all PromptServer imports in a try/except ImportError block.


Roadmap

  • [x] Five typed parameter nodes (Int, Float, String, Combo, Seed)
  • [x] Matrix (Cartesian) and linear (zip) combination modes
  • [x] Automatic labeled 2D and linear comparison grids
  • [x] PNG metadata embedding (JSON + A1111-compatible string)
  • [x] Wildcard expansion (__name__ files and {a|b} inline)
  • [x] Live progress overlay in the ComfyUI canvas
  • [x] Batch cancellation via HTTP API
  • [x] Full unit test coverage for all core modules
  • [ ] Persistent experiment history — SQLite-backed log of batch configurations and result paths, queryable across sessions
  • [ ] Human preference scoring — drag-to-rank or thumbs-up/down UI embedded in the canvas, feeding into a lightweight preference model
  • [ ] GitHub Actions CI — automated test runs on push and pull request
  • [x] ComfyUI Manager official registry listing

License

Distributed under the MIT License. See LICENSE for full terms.


Contact

Jason Tran

Run ComfyUI workflows without the setup

No installs, no CUDA version roulette, no GPU sitting idle on your bill. Bring a workflow and run it in the browser.

Learn more