Nodes/AsyncOutput/Collection
ComfyUI Node

Collection

Park every string a batch run produces, then do something with all of them later

By teddy1565·Created 5 months ago·Updated 5 months ago· 0
Collection
    • passthough_output
    incoming_input
    key_id

    Collection (class AsyncOutputCollect) is the memory-write half of the little "Promise.all" pattern this pack is built around. In a normal ComfyUI workflow each queued run is effectively stateless - a node runs, produces output, and whatever it doesn't pass down a wire is gone. Collection gives you a place to park a string so that after several runs you can act on all of them at once.

    Think of it like Array.push(): every time the node executes, it appends whatever arrives on incoming_input to a list in memory under a key_id, then hands the same string back untouched. Nothing blocks, nothing transforms, nothing gets decided here. It's a side effect with a passthrough, which is exactly why it's the node you drop between your batch step and the thing that waits for the batch to finish.

    How it works

    The node writes into a process-wide Python dict (ASYNC_OUTPUT_STORAGE_DATA) keyed by your key_id. IS_CHANGED returns float('nan'), so ComfyUI always executes it even when the input looks unchanged - which matters because the side effect has to happen every pass. It pairs with AsyncOutputEmitter (the counter that decides "we're done now") and AsyncOutputCallback (the node that finally reads the list back out). The author frames the whole family as JavaScript's Promise.all: spawn N tasks, each one touches Collection, and the callback fires once with all N results joined together.

    The inputs that matter

    Only two, and only one of them is really yours to set:

    • key_id (STRING) - the memory key. Must be non-empty; an empty string makes the node raise "ERROR: key_id property not set." Every node that should share this memory (the matching Emitter and Callback) has to use the same key_id.
    • incoming_input (STRING) - whatever string you're stashing. It's forceInput, so you can't type it, you have to wire something into it.

    Output: passthough_output (STRING), which is literally the input echoed back. Wire it onward so the workflow keeps flowing; the stored copy lives in memory.

    Installing it

    This whole pack is zero-dependency - no requirements.txt, no model downloads, nothing to pip install. In ComfyUI Manager, search "AsyncOutput" and install, then restart. Or do it by hand:

    cd ComfyUI/custom_nodes
    git clone https://github.com/teddy1565/ComfyUI-AsyncOutput
    

    Restart ComfyUI and it's in the menu under AsyncOutput/Deprecated(ComfyUI NOT Turing complete)/String.

    Where people get burned

    Two things to know before you lean on this node. First, the author literally marked the whole AsyncOutput family deprecated in the category name, and the code header says "NOT RECOMMENDED USE, because ComfyUI not real support change status in upstream on a workflow." What that means in practice: all the state lives in Python process memory, so it dies on restart, and by default the pack wipes every dict at the start of each run (that's the "auto reset" behavior - see AsyncOutputGlobalAutoReset). So the collect-then-callback flow works when everything happens inside one queued run, not across runs you expect to remember each other.

    Second, if your collection comes back empty, the usual culprit is the auto-reset firing between the collect and the callback. If you're running a multi-run loop you generally want auto-reset off and manual cleanup on.

    There's also a non-deprecated sibling, BatchIteratorStringCollection, that does the same job against a separate dict - if you're starting fresh, that's the one to reach for.

    CategoryAsyncOutput/Deprecated(ComfyUI NOT Turing complete)/String

    Inputs (2)

    NameTypeDefaultDescription
    incoming_inputSTRING
    key_idSTRING

    Outputs (1)

    NameTypeDescription
    passthough_outputSTRING