Batch Save Image
File a picture into a folder decided upstream (and keep the original bytes)
- image
- image
- saved_path
- written
Here's the gap Batch Save Image fills. ComfyUI's stock SaveImage writes into ComfyUI/output/ with an auto-incrementing prefix - great for generating, useless for sorting. Batch Save Image takes a path that some other node computed and writes, moves or copies the picture there, which is how a folder of 400 renders ends up in keep/ and reject/ without you opening any of them.
What it does, and why move is the interesting mode
Three modes:
save- encode the image tensor into a new file. Use this when the graph changed the picture (inpainted, upscaled, colour corrected).formatdecides the container:keep(the source file's extension, PNG if unknown),png,jpg,webp, withqualityfor the lossy two.move- move the original file from where the loader found it into the target folder. The source folder empties as the batch runs, and what's left over at the end is exactly the set of pictures nothing decided about. That's a genuinely nice way to work: you don't review the accepts, you review the residue.copy- same, but the source stays intact.
move and copy hand the original bytes over untouched. Your generator's JPEG is not re-encoded, no quality is thrown away, and the folder keeps whatever the original file already carried. save is the only mode that writes pixels, and it's the only one where format and quality do anything.
Inputs
directory- the destination. Wire it to Batch Router'starget_diror to the loader'spass_dir/fail_dir; typing paths by hand here is how you end up with a secondrejectfolder one level off.source_path- the loader's output. Required formoveandcopy, ignored forsave. This is the single most common "why did nothing happen" cause with this node.report- an upstream report string, written as a.txtsidecar next to the picture. Route Reality Check → Router → here and the folder records why each file landed where it did. Same basename-plus-.txtpairing the training tools use for captions; handy to read, harmless to everything else.filename_prefix- prepended to the name. Empty keeps the original filename, which is usually what you want when you're sorting rather than generating.overwrite- off by default, so a colliding name gets_001,_002,…. Turn it on only if you genuinely want the existing file gone.enabled- off makes the node do nothing and pass the image through. That's for a fork where one branch should stay idle while you test the other.
Outputs
image (pass-through, so you can chain this mid-graph), saved_path (the file that was actually written - feed it into filenames or logs), and written (boolean). The node is an output node, so it always executes, which is exactly what you want from the thing that does the filing.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/ping1979ping/comfyui-FVMtools
Restart ComfyUI, or use ComfyUI Manager and search comfyui-fvmtools. No extra pip packages for any of the batch nodes - the pack's requirements.txt (insightface, onnxruntime-gpu, opencv-python) is for the face tools.
Where people get burned
Mixing move with a loader you've also pointed at the same folder is fine, and that's the point - the loader tracks a list of finished filenames rather than a counter precisely so the folder can shrink under it. What is not fine is running a second tool over the folder at the same time.
move is a real move, with no recycle bin behind it. Run it on a folder of originals before you're confident in your router and you'll be restoring from backup.
And a quiet one: keep in save mode reuses the source extension, so an all-JPEG input folder gives you JPEG output. If you're building a set you intend to edit later, set format to png deliberately rather than inheriting whatever the generator's export format happened to be - PNG is the only container that round-trips ComfyUI's embedded workflow.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| directory | STRING | Target folder — wire this to the router's target_dir or the loader's pass_dir/fail_dir. | |
| mode | COMBO | move | save: write the image tensor as a new file. move: move the original file (tidies the source folder). copy: copy the original, source stays. |
| filename_prefix | STRING | Prepended to the filename. Empty keeps the original name. | |
| format | COMBO | keep | Output format in save mode. keep: reuse the source file's extension, PNG if unknown. |
| quality | INT | 951–100 | JPEG/WebP quality in save mode. |
| overwrite | BOOLEAN | false | Off: a colliding name gets _001, _002, … On: the existing file is replaced. |
| enabled | BOOLEAN | true | Off: do nothing and pass the image through. Lets one branch of a fork stay idle. |
| imageopt | IMAGE | Required for save mode. | |
| source_pathopt | STRING | The loader's source_path. Required for move/copy. | |
| reportopt | STRING | Written next to the picture as a .txt sidecar, so the folder records why each file landed there. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| saved_path | STRING | — |
| written | BOOLEAN | — |