Save Image Transceiver📡
Save an image to nowhere — shared memory instead of a PNG file
- image
- seed
- channel
SaveImageTransceiver is the "write" half of a two-node pair for shipping images between ComfyUI processes without ever encoding a file. Feed it an IMAGE tensor and a channel name, and it copies the pixels into OS shared memory instead of saving a PNG to ComfyUI/output. Then LoadImageTransceiver, on the same machine, pulls that exact tensor back out by name and drops it into another graph as a normal IMAGE.
Why would you bother? The README's framing is the real one: when you're processing a large number of requests, the stock SaveImage/LoadImage nodes get IO-limited - every image goes through an encode/decode and a disk write. If you have one ComfyUI instance rendering and another one consuming (say, a queue worker feeding frames onward), passing pixels through memory instead of the filesystem removes that bottleneck. If you don't have a multi-process setup, you don't need this pack, and honestly most people don't. It's a single-commit, "UNDER CONSTRUCTION" utility from one author with essentially zero community footprint. It earns its keep only in the exact scenario above.
One hard constraint up front: shared memory lives on a single host. Both processes must run on the same machine (and the same OS - no crossing containers or WSL). This is not a network transfer tool.
What it actually does
Under the hood the pack leans on the author's transceiver PyPI library, which wraps Python's multiprocessing.shared_memory. The node detaches your tensor, moves it to CPU, converts it to numpy, and writes it into a block named transceiver-<channel> - raw array bytes plus a small metadata footer holding dtype and shape so the read side can reconstruct it. No compression, no format, just pixels in memory.
The inputs
image(IMAGE) - the tensor to publish. This is the one that matters; wire your final image here.channel(STRING, default"channel") - the name of the shared-memory slot. The Load side must use the identical string, character for character.seed(INT) - required but unused by the code; the frontend turns it into a seed-style widget, so treat it as a "re-publish" bump rather than an actual parameter.
Its only output is a channel string - a pass-through that confirms which slot you wrote to.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/nat-chan/comfyui-transceiver
cd comfyui-transceiver
pip install -r requirements.txt # pulls in the 'transceiver' library
Restart ComfyUI after. ComfyUI Manager should find it by searching "ComfyUI-Transceiver", though the clone is the guaranteed path. There are no model downloads and no heavy dependencies - just Python 3.10+ plus numpy/torch you already have.
The traps
This is where the pack's youth shows. Writes use create=True and nothing ever calls unlink(), so a shared-memory block survives the process that made it. Write to a channel, run again, and the second write to that same name can fail because the block already exists - the library's own code has a TODO admitting it doesn't handle re-creation. Fresh channel names or a ComfyUI restart are the workarounds. Ordering also matters: the reader raises an error if it runs before this node has written, so across processes make sure the writer publishes first. And there's no locking - two writers on one channel is a race you own. The /transceiver websocket route bundled in the code is stubbed out (the read/write calls are commented out and it returns dummy data), so don't plan around it.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| channel | STRING | channel | — |
| image | IMAGE | — | |
| seed | INT:seed | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| channel | STRING | — |