BD Save Batch
One batch, N files, and it filters what passes downstream
- images
- alpha_mask
- saved_count
- saved_paths
- passed_images
- passed_labels
- preview_images
- status
- preview_alpha
An IMAGE batch in ComfyUI is one tensor with a bunch of frames in it, and the built-in SaveImage will happily write all of them as _00001, _00002, _00003… which tells you nothing. BD Save Batch is the BrainDead fix: it saves each frame as its own file with a meaningful label, and - the part that makes it genuinely clever - it can filter which frames get saved and which get passed downstream, independently. You don't just batch-save; you batch-save and route.
What it is
A save node that takes an images batch plus a labels list (one per line, aligned with frames) and writes one file per frame, using each label as the suffix. Its README-blessed pairing is with BD GLSL Batch: feed it fc1_batch + iteration_names and four GLSL variants (_light, _medium, _dark, _zombie) land as four distinct files from one node and one wire.
How it works
Frames and labels zip together: label light → suffix _light (with label_prefix default _ controlling the separator). If there are more frames than labels, the leftovers save with an empty suffix or a numeric fallback; extra labels are ignored. Then the two filters:
save_only- comma-separated filter of which frames actually touch disk: indices (0,3) or labels (light,zombie) or mixed (0,zombie). Empty = save everything.pass_only- comma-separated filter of which frames flow out thepassed_imagesoutput, same syntax. Independent fromsave_only, so you can savelight,zombieto disk but only passzombiedownstream for post-processing.
That decoupling is the reason to use this node over a generic batch save: one batch can serve both as the archive and as the pipeline.
Inputs that matter
images- the batch. That's it for required.labels- one per frame, in order.save_only/pass_only- the filters above.context_id- matches a BD Save Context (auto-picks if exactly one is registered).format- PNG default, others available.skip_if_exists- don't overwrite.alpha_mask/invert_alpha/save_alpha_separately/alpha_slots/embed_alpha- the alpha family. Bake a mask into the saved alpha (white = opaque), write sidecar_alpha.pngfiles, and target only specific slots. If your source is already RGBA, the embedded alpha survives automatically - no mask wiring needed.
Outputs: saved_count, saved_paths (newline-joined absolute paths in batch order - great for feeding an exporter), passed_images + passed_labels (the routed subset), preview_images (the unfiltered passthrough - wire it to a PreviewImage to sanity-check before production), status, and preview_alpha (the alpha channel rendered as RGBA for inspection).
The gotcha
preview_images is deliberately unfiltered - it ignores save_only/pass_only - so if you wire it to a PreviewImage node and forget it in production, you're previewing every frame on every run. The tooltip says it plainly: disconnect or bypass the preview node when you go live. Cheap mistake, mildly annoying cleanup.
Installing it
ComfyUI Manager: search "BrainDead" → install. Manual:
cd ComfyUI/custom_nodes
git clone https://github.com/BizaNator/ComfyUI-BrainDead
cd ComfyUI-BrainDead
pip install -r requirements.txt
Restart, find it under 🧠BrainDead/Cache. No extra dependencies. If your batch comes out of a node that doesn't label its frames, the labels widget is just text - type them in the same order as the batch, and remember pass_only is your friend when only one tone should flow to the next stage of the graph.
Inputs (14)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | IMAGE batch tensor (B, H, W, C). Each frame is saved as a separate file. | |
| labels | STRING | light medium dark zombie | One label per line, aligned with batch frames. If the labels list has FEWER entries than the batch size, remaining frames save with empty suffix (or numeric fallback). If MORE labels than frames, extras are ignored. |
| save_onlyopt | STRING | Comma-separated FILTER of which frames to SAVE TO DISK. Two formats accepted: Indices: '0,3' = save only frames 0 and 3 (skip 1, 2) Labels: 'light,zombie' = match labels list, save those Mix is fine: '0,zombie'. Empty (default) = save ALL frames. Use to avoid duplicate copies of tone-independent outputs (e.g. fc3 only needs index 0; fc0/fc2 only need indices 0 and 3). | |
| pass_onlyopt | STRING | Comma-separated FILTER of which frames to PASS DOWNSTREAM via the passed_images output. Same syntax as save_only — indices, label names, or mixed. Empty (default) = pass ALL frames downstream. Independent from save_only — you can SAVE different frames than you PASS. Example: save_only='light,zombie' + pass_only='zombie' = saves 2 to disk, but only the zombie frame flows downstream for post-processing. | |
| label_prefixopt | STRING | _ | Prepended to each label before becoming the suffix. Default '_' so label='light' → suffix='_light'. |
| context_idopt | STRING | Match a BD_SaveContext id. Empty + exactly one context registered = auto-pick. | |
| formatopt | COMBO | png | Output file format. |
| skip_if_existsopt | BOOLEAN | false | If True, don't overwrite existing files (reports their path). |
| custom_varsopt | STRING | Extra context variables layered over the saved batch. One per line as key=value. Example: subfolder=SR pass=4k | |
| save_alpha_separatelyopt | BOOLEAN | false | Also write the alpha channel as a standalone greyscale PNG alongside the main file, named with the same suffix + '_alpha'. Source of the alpha pixels: • alpha_mask wired → uses the mask (after invert_alpha) • no mask wired, image has 4 channels (RGBA) → extracts the embedded A channel • no mask wired, image is RGB (3ch) → no alpha to extract; this output is skipped NOTE: the _alpha.png is a RAW greyscale representation — white pixel = opaque area, black pixel = transparent area. It is NOT a composited preview; open the main RGBA PNG in a viewer that supports transparency to see the actual cut-out. |
| alpha_maskopt | MASK | Bake this mask into the saved file's alpha channel before writing. Convention: WHITE (1.0) = OPAQUE, BLACK (0.0) = TRANSPARENT. Face mask (white face, black background) → face is opaque, background is cut out. Background mask (white background, black face) → use invert_alpha=True. If you already have an RGBA image (4-channel), you do NOT need to wire alpha_mask — the embedded alpha is preserved automatically when saving. The upstream image tensor is NOT modified — transparency is baked only in the saved file. Accepts batched masks (B, H, W); single (H,W) or (1,H,W) applies to all frames. | |
| invert_alphaopt | BOOLEAN | false | Flip the mask polarity before baking as alpha. Use when your mask has white=background / black=subject and you want the subject opaque. |
| alpha_slotsopt | STRING | Comma-separated labels or indices of slots that receive alpha treatment. Same syntax as save_only — label names, 0-based indices, or mixed. Controls TWO things for each slot: 1. alpha_mask baking — only matching slots have the mask baked in. 2. save_alpha_separately — only matching slots write a sidecar _alpha.png. Empty (default) = all saved frames get alpha treatment. Example: 'light,image1' — only those two slots save with alpha; the rest save as plain RGB even if alpha_mask is wired. RGBA images (C=4) always preserve their embedded alpha in the main file regardless — this setting only controls the baking and sidecar steps. | |
| embed_alphaopt | BOOLEAN | true | Embed the alpha channel into the saved MAIN image (RGBA). Default True = existing behavior. Set False to write the main image as RGB only — its RGB is saved as-is (e.g. the subject flattened on pure black / white / a Voronoi edge-fill) WITHOUT using the alpha as transparency. The alpha is still produced for save_alpha_separately (sidecar _alpha.png) and the preview_alpha output, so you can keep the mask as a separate file while the image stays fully opaque. Added last so it does not shift existing workflows' widget order. |
Outputs (7)
| Name | Type | Description |
|---|---|---|
| saved_count | INT | Number of files successfully written. |
| saved_paths | STRING | Newline-joined list of absolute paths of saved files, in batch order. |
| passed_images | IMAGE | IMAGE batch containing only the frames matching pass_only filter (or the full input batch if pass_only is empty). Wire downstream for post-processing of selected frames (e.g. one tone to parts compose). |
| passed_labels | STRING | Newline-joined labels of the frames passed downstream, in order. |
| preview_images | IMAGE | UNFILTERED passthrough of the full input batch (all N frames). Useful for wiring to a PreviewImage node during testing to visually verify the GLSL output before saving. Disconnect or bypass the downstream preview node in production. Independent from save_only/pass_only. |
| status | STRING | Human-readable summary of what was saved/skipped/errored/passed. |
| preview_alpha | IMAGE | RGBA IMAGE batch of the alpha channel for each saved frame — white pixels on a transparent background (same format as the _alpha.png on disk). One frame per saved slot, in save order. Wire to PreviewImage to inspect the transparency cutout, or downstream to BD_PackChannels / compositors. Slots without alpha treatment output a fully-transparent (zeros) frame. |