NO8D save
Image-plus-caption pairs for training sets
- images
When you're building a LoRA training set, the file convention is ruthless: every image needs a same-basename caption file next to it - 0001.png and 0001.txt - and the trainer walks the folder reading the sidecars. That pairing is the whole ballgame, and doing it by hand is miserable. NO8D save (class NO8DSaveImageTextDataset) is the node that produces exactly those pairs: feed it images and a caption, and it writes the image plus its matching .txt into a folder, with filenames you control.
The name undersells it slightly. Beyond the dataset use case, it's a full save node - you pick the folder, the format, the quality, and how the filename is built - so it also works as a plain organized-save replacement when you want predictable names and captions.
What you set
folder_path- where the files land. The node creates it if it doesn't exist.name_parts_json- the filename recipe, as JSON. This is the drag-to-reorder part list: fixed text, source filename, date/time, and size class. The default is a single empty fixed part, and you edit it through the node's UI (each part is{"variable": "..."}or{"text": "..."}). Parts build the basename in order; the source filename variable is what keeps dataset images recognizable when they came from a generation batch.image_format- png, jpg, or webp.quality- 1–100, default 100.embed_metadata- on by default. Writes the caption/metadata into the image file's metadata as well as the sidecar.caption(optional) - the text to save alongside each image. One caption per image in a batch, or one shared caption.metadata(optional) - extra metadata text, separate from the caption.
There are no outputs - this is an output node; its result is the files on disk.
How it works
Each image in the batch gets a basename built from the name parts, sanitized to be filesystem-safe, with collision handling (if name.png or its .txt already exists, it gets a unique suffix rather than silently overwriting). It writes the image at your format/quality, and when a caption is connected it writes basename.txt alongside with the caption plus a trailing newline - exactly the sidecar convention kohya, ai-toolkit, and OneTrainer all expect. The .txt extension matters; it's the safe default across trainers. If embed_metadata is on, the metadata also rides inside the image file, which is a nice belt-and-suspenders for tools that read embedded tags.
Where it fits
The natural pipeline in this pack: NO8D-Load-images loads a batch, a captioner (or NO8D-Prompt with a vision model) writes captions, and this node saves the pairs. It's also the right endpoint for a captioning workflow that generates images and captions in one pass - each run produces a ready-to-train folder. For the dataset audience: it respects the "same basename, .txt sidecar" rule that image-io-metadata calls the stable convention across every trainer.
Install and gotchas
cd ComfyUI/custom_nodes
git clone https://github.com/no8d/ComfyUI-NO8D-controls.git
python -m pip install -r requirements.txt
ComfyUI Manager → "NO8D-controls". No models. The honest gotchas: captions are only written when a caption is connected - no caption means images with no .txt, which trainers warn about; and if you save to jpg or webp, remember those formats can't carry the full workflow metadata the way PNG does, so keep png for anything you might want to round-trip back into ComfyUI.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| folder_path | STRING | — | |
| name_parts_json | STRING | [{"variable":"none","text":""}] | — |
| image_format | COMBO | png | 3 options: png, jpg, webp |
| quality | INT | 1001–100 | — |
| embed_metadata | BOOLEAN | true | — |
| captionopt | STRING | — | |
| metadataopt | STRING | — |
Outputs (0)
No outputs