Dynamic Prompt Composer
Batch 32 images, every one a different prompt — no LLM required
- prompt
The name sounds like another "AI writes your prompt" gizmo, but it's the opposite of that. Dynamic Prompt Composer never calls an API, needs no key, and doesn't touch an LLM. It's a plain text mixer: you split your prompt into independent sections, drop a few options into each, and every run it picks one from each section and hands you one clean line of text. Queue a batch of 32 and you get 32 variations of the same idea without writing a single extra prompt.
It's the structured sibling of the old A1111 {this|that|the other} bracket trick that people use to build character reference libraries - batch a fixed seed and get the same person across different cameras, lighting and moods. The difference: inline braces only expand if the text encoder actually knows wildcard syntax, and many don't (SDXL CLIP won't; a Qwen or T5 encoder definitely won't). This node solves that by doing the picking in Python and emitting plain text, so the output wires into literally any encoder.
How it works
Each section is an independent prompt block: subject, style, lighting, whatever. You list options separated by newlines or | characters, and the node splits on both. Empty sections are skipped, and every chosen piece is joined into a single line with spaces - so the output is one tidy STRING you can feed straight into CLIP Text Encode or any STRING input.
Each section has its own mode, and this is where the node earns its keep:
random- true random every run. Theseedinput is ignored. Non-reproducible, on purpose.random (seed)- random, but seeded. Same seed, same pick, always.increment- cycles through your options in order, starting atstart_index.fixed- always picks the option atstart_index.
Two mechanism details worth knowing. First, the node always re-executes when any section is in a random or increment mode, so it re-rolls even if you run with an identical seed. Only when every section is fixed does it cache based on the seed. Second, increment counters reset between batches - the node hooks the queue and wipes them when a new queue starts. See the gotchas, because that last part bites people.
The inputs that actually matter
The only required input is seed - a big INT, 0 to 2^64−1, used by random (seed). Then you get up to 20 sections, each with three inputs: the multiline section_N text box, section_N_mode, and section_N_start_index. The one output is prompt, a STRING.
A fresh node shows three sections (there are Add/Remove Section buttons), but the code accepts 20 - the README says 10, which is stale. Trust the code on that one.
Wiring it up
Connect prompt to your text encoder's text input. If you're running a batch, tie the node's seed to your KSampler seed when you want reproducibility. A setup that works well: subject and style sections in random (seed) mode, one "camera/lens" section in increment mode so a 16-image batch guarantees you try every lens, and a fixed start_index on anything you're not ready to shuffle.
Install
No models, no dependencies, nothing to download - the requirements list is empty. Either of:
cd ComfyUI/custom_nodes
git clone https://github.com/Alatza/ComfyUI-DynamicPromptComposer
…then restart ComfyUI, or open ComfyUI Manager and search "Dynamic Prompt Composer". It lands under the prompt category. Requires Python 3.10+, MIT licensed.
Gotchas
randomignores the seed. If you set the node's seed and expect the same prompt to come back, you're in the wrong mode - that'srandom (seed).incrementlooks broken until you batch. Because counters reset at the start of each batch, a single isolated run always shows element atstart_index. Queue 5+ images and it suddenly makes sense. Interrupted runs also reset, so it never drifts.- Separator is a space. On tag-based models (Illustrious, Pony) where prompts are comma-separated, remember to bake commas into your options, or you'll get
"long hair blue eyes"soup. - The console is your friend. Every pick is printed as
[DynamicPromptComposer] section_2 (random (seed)): 'chosen', so when an output looks wrong you can see exactly what got selected and why.
Inputs (61)
| Name | Type | Default | Description |
|---|---|---|---|
| seed | INT | 00–18446744073709550000 | — |
| section_0opt | STRING | — | |
| section_0_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_0_start_indexopt | INT | 00–99 | — |
| section_1opt | STRING | — | |
| section_1_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_1_start_indexopt | INT | 00–99 | — |
| section_2opt | STRING | — | |
| section_2_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_2_start_indexopt | INT | 00–99 | — |
| section_3opt | STRING | — | |
| section_3_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_3_start_indexopt | INT | 00–99 | — |
| section_4opt | STRING | — | |
| section_4_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_4_start_indexopt | INT | 00–99 | — |
| section_5opt | STRING | — | |
| section_5_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_5_start_indexopt | INT | 00–99 | — |
| section_6opt | STRING | — | |
| section_6_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_6_start_indexopt | INT | 00–99 | — |
| section_7opt | STRING | — | |
| section_7_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_7_start_indexopt | INT | 00–99 | — |
| section_8opt | STRING | — | |
| section_8_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_8_start_indexopt | INT | 00–99 | — |
| section_9opt | STRING | — | |
| section_9_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_9_start_indexopt | INT | 00–99 | — |
| section_10opt | STRING | — | |
| section_10_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_10_start_indexopt | INT | 00–99 | — |
| section_11opt | STRING | — | |
| section_11_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_11_start_indexopt | INT | 00–99 | — |
| section_12opt | STRING | — | |
| section_12_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_12_start_indexopt | INT | 00–99 | — |
| section_13opt | STRING | — | |
| section_13_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_13_start_indexopt | INT | 00–99 | — |
| section_14opt | STRING | — | |
| section_14_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_14_start_indexopt | INT | 00–99 | — |
| section_15opt | STRING | — | |
| section_15_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_15_start_indexopt | INT | 00–99 | — |
| section_16opt | STRING | — | |
| section_16_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_16_start_indexopt | INT | 00–99 | — |
| section_17opt | STRING | — | |
| section_17_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_17_start_indexopt | INT | 00–99 | — |
| section_18opt | STRING | — | |
| section_18_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_18_start_indexopt | INT | 00–99 | — |
| section_19opt | STRING | — | |
| section_19_modeopt | COMBO | 4 options: random, random (seed), increment, fixed | |
| section_19_start_indexopt | INT | 00–99 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| prompt | STRING | — |