Nifty Save Image
Save where you actually want, and keep the metadata
- images
- meta_bundle
- images
- filename
Core Save Image puts everything in output/ and gives you one text box for the prefix. That's fine until you're generating grid tests, upscale passes and A/B comparisons in the same session, at which point you want the 4x upscales in their own folder and the filenames to say which CFG they came from.
This one does that, and it's careful about the thing that actually matters with PNGs in ComfyUI: the metadata. A ComfyUI PNG isn't just pixels - the workflow, the prompt and the node values are inside it as text chunks, which is why dragging a saved image back onto the canvas rebuilds the graph. Save through something that re-encodes, and that's gone. This node writes those chunks properly, plus any bundle you hand it.
Inputs and outputs
images- what to save. Single image or a batch.filename- prefix, and it understands placeholders:%date:yyyy-MM-dd%plus%width%,%height%,%year%,%month%,%day%,%hour%,%minute%,%second%,%batch_num%.filename_suffix- appended before the counter. This is the small feature core's node lacks, and it's the one that lets you generaterender_sharpenedandrender_softenedfrom the same base name.folder- path relative to the ComfyUI root (output,../output) or absolute (D:\output). Created if it doesn't exist.save_metadata- default on.overwrite- default off.meta_bundle(optional) - a bundle, embedded under the keymeta_bundlealongside the prompt and workflow chunks.
Outputs: images passes straight through, so you can keep previewing or chain further, and filename returns the comma-separated list of what was written - useful for printing or for feeding a downstream node.
How it behaves in the details
The counter is its own. Rather than ComfyUI's global counter, the node scans the destination folder for files matching the base name and continues from the highest number it finds - so after a restart, or on a folder you saved into last month, it keeps counting instead of starting over at _00001.
overwrite: True removes the counter entirely, but it's narrower than it sounds: it's ignored for batches of more than one image (those always count up), and the tooltip warns about the real trap - if the node runs more than once in a session, which is exactly what happens when a list output drives it, each run overwrites the file the previous run just wrote. For grid sweeps, leave overwrite off.
Folder-wise, anything outside ComfyUI's registered output directory still gets saved; you just don't get the thumbnail in the node, because the preview is built from the registered output path. Don't read the missing preview as a failed save.
Why you'd route a bundle into it
meta_bundle is how this node pairs with the rest of the pack. Sweep CFG and steps through Bundle Grid List, and each generated PNG carries the exact values that produced it in its own metadata - so the file is self-describing six months later when you've forgotten what cfg4-20 meant. That's the same "the image is the project file" property the KB's image-I/O doc is built around, extended to your own keys.
If you're saving for sharing, leave save_metadata on. If you're saving something you'd rather not ship a workflow with, turn it off deliberately - that's the privacy switch, and it's per-node rather than global.
Installing it
ComfyUI Manager → search Nifty Nodes, or:
cd ComfyUI/custom_nodes
git clone https://github.com/Stibo/comfyui-nifty-nodes
Restart ComfyUI. The pack's declared dependencies (color-matcher, imageio-ffmpeg) are installed by Manager and are not used by this node. Source is written against ComfyUI's newer V3 API, so no NODE_CLASS_MAPPINGS-style mapping dict is expected. It's a single-author pack with very little community footprint; the README is short and accurate, and the code is legible.
Where people get burned
- A stray
%in the filename. The date parser only understands its own token list (yyyy,yy,MM,dd,hh,mm,ss). A percent sign you meant literally may get eaten or left dangling. - Renaming files afterwards. Anything that re-encodes - a converter, a screenshot, a host that recompresses - strips the text chunks. Reddit's re-served copies are the classic example; your original file keeps the workflow, the repost doesn't.
filenameoutput is a list in a string. It's comma-separated, so don't feed it into a filename slot expecting one clean name.- Batch + overwrite. Covered above, but it's the single most likely way to lose work with this node: batch is always counted, single-run repetition is not.
- Very large batches and compress_level 4. The pack deliberately saves at a modest compression level for speed, so PNGs are a bit fatter than a maximum-compression save of the same pixels.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | The images to save. | |
| filename | STRING | ComfyUI | The prefix for the file to save. Supports date placeholders such as %date:yyyy-MM-dd% as well as %width%, %height%, %year%, %month%, %day%, %hour%, %minute%, %second% and %batch_num%. |
| filename_suffix | STRING | Appended to filename before the automatic counter, e.g. to tell apart variants of the same base name like _upscaled or _sharpened. | |
| folder | STRING | output | Relative to the ComfyUI root ('output', '../output') or an absolute path (e.g. D:\output). Paths outside the registered output directory won't show a node preview thumbnail, but the file is still saved. |
| save_metadata | BOOLEAN | true | Embeds prompt/extra_pnginfo and meta_bundle as PNG text chunks. |
| overwrite | BOOLEAN | false | If disabled, a counter (_00001, _00002, ...) is appended so existing files are never replaced. If enabled, no counter is appended and an existing file with the same name is overwritten. Ignored for batches with more than one image, which are always counted up. If the node is executed several times (e.g. via list outputs), each execution overwrites the file of the previous one. |
| meta_bundleopt | BUNDLE | Optional metadata dict, embedded together with prompt/extra_pnginfo under the key 'meta_bundle' (only when save_metadata=True). |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |
| filename | STRING | Comma-separated list of all saved filenames. |