SaveLatentsMemory
Hand the raw latent to your own code
- latents
Same pack, same idea as SaveImagesMemory, one crucial difference: where its sibling writes a finished PNG, this node writes the raw latent tensor that came out of your sampler. Still compressed, still in latent space, never decoded to pixels. That's the whole point - if whatever sits on the other end of your pipeline is more neural net (another ComfyUI instance, your own sampler loop, a script that wants to keep sampling instead of look at a picture), the VAE decode is exactly the step you don't need. Why burn a decode, ship a PNG, and encode it again on the other side when you can just pass the tensor?
It's another niche API/interop tool from hnmr293 (the sd-webui-cutoff and ComfyUI-nodes-hnmr developer), and the README doesn't pretend otherwise: intended for use via API. If you're a UI-clicking workflow person, this is not for you, and it definitely doesn't "save memory" in the VRAM sense - that name trap is worth catching now.
What it actually does
The node attaches to a named multiprocessing.shared_memory.SharedMemory segment that your receiver process created in advance, then torch.saves the latent's samples tensor - moved to CPU first - into it. The layout is dead simple:
- 8 bytes: the length of the data that follows (native endian)
- the rest: the
torch.savebytes
To get the tensor back on the other side you torch.load those bytes. One honest caveat from the source: only the samples tensor is written. ComfyUI stashes a noise_mask alongside latents in inpainting workflows, and that does not make the trip - so don't use this to ship masked latents around.
The inputs
Three, same shape as the sibling node:
- name (STRING) - the shared memory tag. Must exactly match the segment your receiver created.
- latents (LATENT) - wire from a sampler.
- dummy_input (INT, optional) - the rerun trigger, because a node with no output can otherwise get cached and skipped on re-runs.
No outputs; it's a terminal node. It runs, writes, returns an empty dict.
Installing it
Identical to the pack's other node - ComfyUI Manager → Install Custom Nodes → search ComfyUI-SaveMem, restart. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/hnmr293/comfyui-savemem
Restart and you're done. No extra pip packages (torch, numpy, PIL are all already in ComfyUI), no models to download, MIT-licensed.
Common issues
- FileNotFoundError - the segment doesn't exist yet. Create it on the receiver side first, per the README.
- "Buffer size X is smaller than required Y" - latents are bigger than people expect. An SDXL latent at 1024² is 4×128×128 channels of fp32, so on the order of 16 MB before you even add pickling overhead. Size your segment accordingly, or you'll get a runtime error and a half-written header.
- Stale reads on re-run - bump
dummy_input. - The pickle caveat -
torch.loadexecutes pickled code. Only load segments you created yourself; don't accept shared memory from something you don't trust. And since shared memory is per-machine, the reader has to be on the same box.
A receiver that hands the tensor back to ComfyUI-style dicts:
import io, struct, torch
from multiprocessing import shared_memory as sm
shim = sm.SharedMemory(name="my_latent") # you created it earlier
length, = struct.unpack("=Q", shim.buf[:8])
samples = torch.load(io.BytesIO(bytes(shim.buf[8:8+length])), map_location="cpu")
shim.close()
latent = {"samples": samples} # feed straight into a Decode node, or keep sampling
It's a tool you reach for exactly once you've built the other half of the pipe. When that day comes, it's refreshingly small and honest about what it does.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| name | STRING | name of the shared memory | |
| latents | LATENT | — | |
| dummy_inputopt | INT | 0 | dummy input for rerunning |
Outputs (0)
No outputs