DA_AnySwitch
Let the graph decide which branch is live
- input_1
- input_2
- output
You built a workflow with three ways to generate the same image - a checkpoint branch, a LoRA branch, an upscale branch - and you're tired of unplugging wires every time you want a different one. DA_AnySwitch ends that. Wire all three in, and it forwards whichever one is actually alive.
The shape of it, and why it matters
There are two things people call "a switch" in ComfyUI and they are not the same. An A/B switch has a selector widget - you point it at input 2 and input 2 flows. A fallback switch has no selector at all: it walks its inputs and passes the first one that isn't empty. DA_AnySwitch is the second kind, and the README is upfront that it's "inspired but not based on" rgthree's AnySwitch. This is plumbing in the purest sense - it touches no pixels, and the graph routes itself: mute a branch and the switch quietly moves to the next one.
How it actually works
Two halves, one Python, one JavaScript.
The Python half is about fifteen lines. input_1 and input_2 are declared as optional * inputs - ComfyUI's wildcard type, the escape hatch that lets a socket accept a MODEL, a LATENT, an IMAGE, anything. The function walks kwargs and returns the first value that isn't None. That works because of an engine convention: an optional input you leave unconnected isn't passed to the function at all. Absent, not None-valued. So "first non-null" and "first one I actually plugged in" are the same thing.
The JavaScript half is the part you'll notice. The node declares two slots; the extension watches for a connection and, when the last slot gets a wire, adds input_3. Plug that, get input_4. It never shrinks - a node grown to six slots keeps all six. It also relabels the output: on every connection change it reads the type off the first linked input and rewrites the output socket to match. So the output isn't permanently * - plug a LATENT in and it reads LATENT, which is what keeps a normal typed input downstream happy.
What you get:
input_1,input_2- type*, both optional. Wire whatever you want; more slots appear as you fill them.output- type*, the first non-empty input, or nothing if every slot is empty.
No widget, no seed, no mode.
Install
It's in ComfyUI Manager - search the pack title DemonAlone-JS_Addon-ComfyUI and hit install. By hand:
cd ComfyUI/custom_nodes
git clone https://github.com/DemonAlone/DemonAlone-JS_Addon-ComfyUI
Restart ComfyUI, then hard-refresh the browser (Ctrl+Shift+R). That second step isn't optional: the dynamic slots are a frontend extension loaded from the pack's web/ directory, and a cached page load gives you a node that never grows.
No model downloads, and for this node no dependencies - the pack ships no requirements.txt and its pyproject.toml lists none. (Its video nodes are a different story: Load Video and Video Maker V2 both import av, so a ModuleNotFoundError: No module named 'av' from this pack means you tried those, not this one. The README never mentions it.)
Where people get burned
Bypassing instead of muting. This is the big one. A bypassed node isn't skipped - ComfyUI passes its input straight through to its output. So if you bypass the sampler feeding input_1, the switch can receive a live value from upstream of that sampler, decide the slot is populated, and forward it. rgthree's own account of the same failure: bypass "takes an input value and passes it to the output," and the switch takes the first non-null value - the bypassed one. You want Mute (Ctrl+M), which genuinely removes the node. Then the input really is empty and the switch moves on. Bypass instead and you get a type error several nodes downstream, pointing at a node that looks innocent.
Ordering surprises. The Python sorts input names as strings before walking them, and input_10 sorts before input_2 alphabetically - so past nine inputs, slot 10 outranks slots 2 through 9. Priority is slot order, not preference. The output label is your only read on which input won, so glance at it before debugging the wrong end of a wire.
Subgraphs. Dynamically grown inputs are known to misbehave once a node gets folded into a subgraph - a long-standing community complaint about this class of node, with rgthree himself confirming "there are reports of Get/Set nodes not working with Any Switches." Test the switch after wrapping branches rather than assuming it survived.
Nodes 2.0. The pack's UI tricks are written against the legacy LiteGraph canvas API - node.addInput, onConnectionsChange. That's the surface the Nodes 2.0 frontend replaced, and where packs written this way are still broken (rgthree's issue 632 was open eight months on). If the slots refuse to grow, switch back to the legacy canvas before filing a bug.
One honest caveat: a node that erases types and picks branches silently is the trade-off the "Please Stop using the Anything Anywhere extension" crowd was angry about. Use it for two or three live branches, not as the spine of a forty-node graph.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| input_1opt | * | — | |
| input_2opt | * | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| output | * | — |