2BZ Use Upscaled If Needed
The switch node that doesn't run both branches
- upscaled
- original
- image
On paper this is a two-line node: take a boolean, return one of two images. ComfyUI already has switch nodes. So why does 2BZ Use Upscaled If Needed (ToobusyUseUpscaledIfNeeded) exist, and why does the pack bother shipping it?
Because the switch nodes you already have cost you the thing you're trying to save.
The trap it fixes
Switch nodes come in two shapes. There's the A/B switch with a selector that passes whichever input you point it at, and there's the fallback switch - rgthree's Any Switch is the canonical one - which walks its inputs and passes the first that isn't empty. Both are correct, useful plumbing, and both have the same property: to hand you one input, ComfyUI has to have evaluated the others. The engine works backwards from the output nodes and computes what's needed. An input you didn't select is still an input.
In a graph where the unused branch is a VOSR 2.0 upscale, that means the upscaler runs, its model loads, and you pay for it every single time - including on the images that were already the right size and needed no pass at all. On the author's 18.7MP character sheet that was the difference between 311 seconds and 65 seconds, and 18GB of VRAM peak versus 12GB.
How it avoids that
Both image inputs are declared lazy: True, and the node implements check_lazy_status. In plain terms: instead of asking for both images, it tells the engine which one it wants after reading use_upscaled. If use_upscaled is true it requests upscaled; if false, it requests original and never looks at the other. The whole decision is return upscaled if use_upscaled else original.
The consequence is the interesting part: when nothing needs enlarging, the upstream VOSR 2.0 node and the model loader feeding it are simply not executed. Not "run and discarded" - not run.
Inputs and outputs
Three required inputs, no optional ones, one output.
use_upscaled- aBOOLEANwithforceInput, i.e. it has to be wired; you can't just flip a widget. In practice it takesneeds_upscalefrom 2BZ Face-Size Scale Plan.upscaled- the enlarged image, the one that comes out of VOSR 2.0. Lazy, so only computed when it's the branch you picked.original- the un-upscaled image, for when no growth was needed.
And out comes a single image, which is just whichever one won. Feed it to an Image Scale node, then into the retouch pass:
2BZ Face-Size Scale Plan
needs_upscale -> use_upscaled
VOSR 2.0 Upscale -> upscaled
Load Image -> original
2BZ Use Upscaled If Needed -> image -> Image Scale -> retouch
That's the whole node. It's not doing clever image work; it's making the graph cheap.
Install
Same as the rest of the pack, and version-gated the same way - this node landed in toobusy 0.5.6:
cd ComfyUI/custom_nodes
git clone https://github.com/nicekriss/toobusy.git toobusy
Restart ComfyUI. If you install through ComfyUI Manager instead, note the README's warning that Manager pulls from the Comfy Registry, and older builds have been pulled from it - you can land on an older release where this node isn't in the menu at all, with no error to explain it. Check custom_nodes/toobusy/pyproject.toml for the version value; if it's below 0.5.6, use the clone or Manager's Install via Git URL with https://github.com/nicekriss/toobusy.
There's nothing to download for this node itself, and no requirements_*.txt from the pack applies. What you do need is on the other end of the wire: the VOSR 2.0 node pack (comfyui-vosr2, in Manager) and SAM3 for the detection that feeds the plan.
Where it bites
It only skips what nothing else consumes. Lazy inputs stop this node from pulling the branch. If some other node in the graph - a preview, a second Save Image, a debugging branch - also reads the VOSR 2.0 output, that branch runs regardless and the savings evaporate. This is the one real gotcha; if the timing doesn't change, look for another consumer of the upscaled image.
forceInput means it won't work as a manual toggle. No widget to click. Wire it to a boolean you can change if you want to force the choice - but if you're just going to hardcode true, you've paid for a node to do nothing.
Don't reach for it as a general switch. Both inputs are IMAGE and both branches must be wired, and there's no * wildcard anywhere in it. It's a purpose-built A/B for one job: is the image already the right size? If your branches are models or latents, use a proper switch node - and accept the cost on the unused side, because you can't get lazy evaluation for free on arbitrary types.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| use_upscaled | BOOLEAN | Face-Size Scale Plan의 needs_upscale | |
| upscaled | IMAGE | 키운 이미지(VOSR 2.0) — 필요할 때만 계산 | |
| original | IMAGE | 원본 — 키울 필요 없을 때 |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |