GS SmartSwitch
The Switch That Grays Out the Branch You're Not Using
- on_true
- on_false
- output
The switch that tells you what it's actually switching
Every ComfyUI user knows the A/B switch trap. You wire two candidate paths - two samplers, two upscalers, two LoRA stacks - into a Switch, flip the boolean, and the inactive branch is technically dead. But its widgets still stare at you, fully editable-looking, begging you to tweak a seed that isn't doing anything. GS SmartSwitch is the native Switch with one extra trick: it walks the graph, figures out which nodes feed only the inactive branch, and grays out every widget on them in place. A dead calculation path stops looking alive.
That matters more than it sounds. The plumbing layer's whole job is fighting repetition and illegibility - this pack's entire pitch is the second one. When a workflow has two methods behind one switch, half the confusion is not knowing which path is live. Graying it out turns "which inputs matter right now?" into a thing you can see at a glance, no title text required.
How it works
Here's the honest part: the Python backend is one line. execute just returns on_true if boolean else on_false - GS SmartSwitch is the native Switch under the hood. All the intelligence lives in the client-side JS, which polls the graph every ~200ms. Each tick it walks upstream from on_true's source and from on_false's source, recursively following input links, then subtracts the two ancestor sets. What's left on each side is that branch's exclusive ancestry. Nodes feeding both branches - say, a shared width/height primitive - are left alone, because they're needed either way.
Two details are worth knowing. It's subgraph-aware: the walker descends into nested graphs, so it works inside a packaged subgraph too - and if a grayed widget is promoted to the subgraph's outer face, the promoted parameter quietly disappears from that outer view while the interior stays visible-but-grayed. And if two SmartSwitches share an upstream node, a widget only goes back to active once every claiming switch has released it, so they can't fight over the same field.
The inputs that matter
Only two widgets are actually on the node, and both are booleans:
- boolean - the switch itself.
truerouteson_truethrough and grays outon_false's exclusive upstream widgets;falsedoes the reverse. - auto_disable - defaults on, so the gray-out behavior is what you get out of the box. Toggle it off and the switch still routes normally, it just stops touching widget appearance. Handy for debugging without rewiring.
on_true and on_false are optional wildcard inputs - they'll accept a latent, an image, a model, anything. The single output passes through whichever branch the boolean picked. Wire it exactly like you'd wire ComfyUI's native Switch, because that's what it is.
Install
Drop the folder into custom_nodes, restart ComfyUI:
cd ComfyUI/custom_nodes
git clone https://github.com/Gerry-Malta/ComfyUI-GerryNodes
Or just search "GerryNodes" in ComfyUI Manager - it's a registered, publishable pack. There are no Python dependencies (dependencies = [] in pyproject), no model downloads, no install script. The whole thing is one small backend class plus one JS file. It shows up under utils/conditional in the node search. That's the entire install story; don't go looking for more.
Where people get burned
The biggest gotcha is that graying out is cosmetic only. The inactive branch's nodes still execute if something downstream forces a queue - this doesn't bypass or mute anything, it just hides the widgets. The README says it plainly: pair it with a bypass/mute-on-boolean node (it name-checks ComfyUI-vslinx-nodes) if your goal is to stop computing, not just stop looking at dead fields.
Detection is structural, not semantic. If a node happens to feed both branches even though conceptually it "belongs" to one, it stays visible on both - which is the safe failure mode (you never lose access to something you need). And because it's poll-based, there's a trivial CPU cost and a hair of latency in exchange for robustness across undo, copy-paste, and fresh loads.
One cosmetic edge case: if a widget had a custom display label before going inactive and in-memory state is lost (a page reload, say), it restores under its default name rather than its custom one. Minor, and it's about the only wart. This pack is brand-new and basically unheard of in the wild - no community threads, zero search impressions - so treat it as a sharp little single-purpose tool, not a staple. For a node this focused, that's fine.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| boolean | BOOLEAN | true | True routes on_true through and grays out on_false's exclusive upstream widgets. False does the reverse. |
| auto_disable | BOOLEAN | true | Turn off to disable the auto gray-out behavior entirely - the switch still routes on_true/on_false normally either way. |
| on_trueopt | * | — | |
| on_falseopt | * | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| output | * | — |