Nodes/BrainDead Nodes/BD Save File
ComfyUI Node

BD Save File

The save node that speaks every type the pack uses

By BizaNator·Created 8 months ago·Updated 3 days ago· 15
BD Save File
  • data
  • alpha_mask
  • data
  • file_path
  • status
filenamesaved_file
skip_if_existstrue
name_prefix
extension
context_id
suffix
custom_vars
save_alpha_separatelyfalse
invert_alphafalse

ComfyUI's built-in SaveImage only speaks IMAGE. BD Save File speaks everything the BrainDead pack actually produces - IMAGE, MASK, AUDIO, LATENT, STRING, TRIMESH - and it's the node that ties the pack's file discipline together. Whether you're caching a mesh, dumping a PBR map, or parking a prompt string next to your renders, one node does it, and it slots into the BD Save Context system so filenames stop being a mess.

What it is

A universal save node: wire in data of almost any type, it picks the right native format and writes it to disk, then hands you back the file_path as a STRING (and passes the data through unchanged). It's the same "save" node the README builds the whole caching/iteration story on.

How it works

The type determines the format - IMAGE → PNG, MASK → PNG, LATENT → safetensors, AUDIO → WAV, STRING → TXT, TRIMESH → PLY. You don't pick the format; it detects it. Where it gets interesting is context integration:

  • With a BD Save Context registered and context_id matched, the path resolves from the context's template plus this node's suffix / filename / name_prefix / custom_vars. One context, N save nodes, all consistent.
  • Without a context (or with zero/multiple contexts registered and an empty context_id), it falls back to legacy behavior: filename + optional name_prefix into the output folder.

The inputs that matter

  • data - the any-type input. This is the whole reason to use it.
  • filename - with a context it overrides %name%/%filename% in the template; without one it's the literal filename.
  • context_id + suffix - _albedo, _shoes, _head. The README suggests wiring suffix from BD For Each Run.label or an iterator's tag for per-iteration filenames.
  • skip_if_exists (default true) - don't clobber existing files; report the existing path instead.
  • extension - override the auto-detected one, for the rare case you want a different container.
  • alpha_mask / invert_alpha / save_alpha_separately - bake a mask into the saved file's alpha channel (white = opaque), and optionally write a sidecar _alpha.png. Conventions matter here: white = opaque, black = transparent, and ComfyUI's LoadImage mask output is the inverse of the subject - flip invert_alpha if your mask has white=background.

Outputs: data (passthrough, so you can chain), file_path (absolute path as a STRING - wire it into anything that wants a path), and status.

Where it shines

The README's example says it best: [BD Prompt Iterator] → [BD Qwen Character Edit] → [BD Save File] with name_prefix: MyCharacter - iterate through a character sheet and land clean, sequentially-named files. And in the PBR pipeline, five maps out of BD Derive PBR Maps all funnel into one context-aware save. If you've ever hunted through output/ for the file that SaveImage_0001 actually wrote, you'll appreciate getting a real path back.

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 beyond what ComfyUI already has - trimesh (for TRIMESH saves) ships with modern ComfyUI, and the audio/latent paths use native ComfyUI formats.

Category🧠BrainDead/Cache

Inputs (11)

NameTypeDefaultDescription
data*
filenameSTRINGsaved_fileWith context: overrides %name% / %filename% in template if set (non-'saved_file'). Without context: legacy filename.
skip_if_existsBOOLEANtrue
name_prefixoptSTRINGWith context: exposed as %name_prefix% in template. Without context: legacy prefix prepended to filename.
extensionoptSTRINGOverride auto-detected extension.
context_idoptSTRINGIf set AND a BD_SaveContext with this id is registered: path is resolved from the context's template + this node's suffix/filename/name_prefix. If empty AND exactly ONE context is registered, that one is auto-used. If empty AND zero or multiple contexts: legacy filename-based behavior.
suffixoptSTRINGPer-save suffix appended after filename (e.g. '_albedo', '_shoes', '_head'). Wire from BD_ForEachRun.label or Iterator.tag for per-iteration filenames. With context: also exposed as %suffix% in the template. Without context: appended literally to filename — caller controls separator (convention: leading underscore).
custom_varsoptSTRINGPer-save extra variables, one per line as key=value. Layered ON TOP of the context's custom_vars (this node's keys override context for matching names). Examples: subfolder=textures materials=metal pass=normal These become %subfolder%, %materials%, %pass% in the template. Empty values resolve cleanly (// → /). Undefined vars stay as %var% literals so you spot typos.
save_alpha_separatelyoptBOOLEANfalseAlso 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_maskoptMASKBake 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_alphaoptBOOLEANfalseFlip the mask polarity before baking as alpha. Use when your mask has white=background / black=subject and you want the subject opaque.

Outputs (3)

NameTypeDescription
data*
file_pathSTRING
statusSTRING