ComfyUI conditionals
Predicates → boolean → branch. How the decision is formed, not where the signal goes after.
Four packs contribute predicate primitives. The split:
| Pack | Primary niche |
|---|---|
comfyui-easy-use |
easy ifElse, easy compare, easy blocker, and the easy is* probes — the broadest, most-used predicate kit |
comfyui-impact-pack |
ImpactCompare + ImpactConditionalBranch (lazy) + ImpactIfNone + ImpactConditionalStopIteration (Impact-iterator loop control) |
comfyui_essentials |
SimpleCondition (ternary), SimpleComparison (typed, epsilon-aware), SimpleMathCondition (boolean from math) |
comfyui-logicutils |
Bit-banging + regex-on-strings logic gates: AContainsB, bitwise And/Or/Xor/Not/Shift, generic Invert |
When to Use This Skill
| Use this skill when... | Use instead when... |
|---|---|
| Forming the boolean/predicate that drives a switch or blocker in a workflow | Routing the signal after the decision is made -> comfy-flow-control |
| Comparing values, combining booleans, detecting null/empty | Computing a numeric (non-boolean) value -> comfy-math-strings |
Sources of truth
custom_nodes/comfyui-easy-use/py/nodes/logic.py— ifElse, compare, blocker, is* probescustom_nodes/comfyui-impact-pack/modules/impact/special_samplers.py— ImpactCompare, ImpactConditionalBranchcustom_nodes/comfyui_essentials/misc.py— SimpleMath / SimpleCondition / SimpleComparisoncustom_nodes/comfyui-logicutils/logic_gates.py— logic gate nodes
Which compare node?
| Need | Best node | Why |
|---|---|---|
Compare two ANY values, any op (==, !=, <, >, <=, >=) |
easy compare |
Multi-op switcher widget, no type lock |
| Compare two INT/FLOAT, return BOOLEAN | ImpactCompare |
Op picker (a=b, a<>b, a>b, a<b, a>=b, a<=b, tt/ff constants) |
| Compare two FLOAT with epsilon tolerance | SimpleComparison (essentials) |
Floats are unsafe under == — epsilon-aware |
| Compare a string against a regex / substring | LogicGateCompareString / AContainsB (logicutils) |
The only regex-on-string predicate available |
Quick math → boolean (e.g. (a+b) > c) |
SimpleMathCondition |
Computes the expression and returns BOOLEAN in one node |
| Detect null / unwired input | easy isNone or ImpactIfNone |
Returns BOOLEAN + passes value through |
| Detect empty mask (all zeros) | easy isMaskEmpty |
Specifically tests MASK type |
| Detect SDXL vs SD1 model | easy isSDXL |
Probes CLIP / pipe and identifies arch |
| Detect file path exists on disk | easy isFileExist |
For input-validation gates |
Type coercion footgun
ImpactConditionalBranch.cond is BOOLEAN. Don't feed it:
SimpleMathConditionoutput → that's FLOAT (0.0 / 1.0) — convert via comparator firsteasy compareoutput → that IS BOOLEAN, fineLogicGateCompareoutput → BOOLEAN, fine- A raw INT from a math node → not BOOLEAN; pass through
ImpactCompare(a > 0) or convert
When in doubt, route through easy compare and pick the comparison operator that yields the boolean you want.
Boolean algebra
For combining multiple predicates into one branch input:
| Operator | Node |
|---|---|
| AND / OR / XOR | ImpactLogicalOperators (op picker) |
| NOT | ImpactNeg |
| Bit-wise AND / OR / XOR / NOT / shift | logicutils LogicGateBitwiseAnd etc. (work on INT, not BOOLEAN) |
| Generic invert (works on any truthy/falsy) | LogicGateInvertBasic |
isMaskEmpty(face_mask) ──┐
▼
ImpactNeg (NOT) ──┐
▼
ImpactLogicalOperators (AND) ──→ ImpactConditionalBranch
▲
isFileExist(reference.png) ────────┘
This combination says: "face mask is non-empty AND reference image exists on disk → run the detailer branch".
Branching
Lazy if-then-else (skips the discarded branch)
| Node | Behavior |
|---|---|
easy ifElse |
BOOLEAN selector, on_true / on_false inputs; only the chosen one is evaluated upstream |
ImpactConditionalBranch |
BOOLEAN cond; lazy tt_value / ff_value inputs |
ImpactConditionalBranchSelMode |
Same, but selection happens at execution time rather than prompt-queue time — needed when cond depends on something computed earlier in the same queue |
These are predicate-side nodes that ALSO act as switches — they
form the boolean and route in one step. If your predicate is simple
(one comparison) and the branches are large (samplers, models),
ImpactConditionalBranch is the cleanest single-node solution.
If the predicate is complex (multi-criteria), form it explicitly in
this skill's primitives, then pass the resulting BOOLEAN to a switch
from comfy-flow-control.
Ternary (compute, don't route)
SimpleCondition (essentials) — given condition, returns value_if_true
or value_if_false. Both inputs are computed (eager), so it's a value
picker, not an execution gate. Use it for selecting between two
constants or already-computed scalars; never for selecting between
sampler chains.
ExecutionBlocker — the kill-path primitive
easy blocker is the canonical "kill this path" node. Behavior:
- Input: any value +
continueBOOLEAN. - If
continue=True: pass the value through unchanged. - If
continue=False: returns anExecutionBlockersentinel.
The sentinel propagates downstream: any node that receives an
ExecutionBlocker on any input is silently skipped (its
execute() is never called). The skip cascades through the rest of
the graph downstream of the blocker.
LoadImage ── easy compare (size > 1024) ─┐
▼
LoadImage ──────────────► easy blocker ───► ResizeImage ─► KSampler ─► SaveImage
▲ continue
When the loaded image is smaller than 1024px, the blocker fires; ResizeImage / KSampler / SaveImage are all skipped without errors.
ExecutionBlocker gotchas
- Preview Bridge swallows the sentinel — see
comfy-flow-controlgotchas. The blocker fires, but a Preview Bridge tee downstream reports nothing visibly, and fails to propagate the abort. UseFastPreview(kjnodes) downstream of a blocker if you need visual confirmation. - Cannot be visualized — there's no "is this currently blocked?"
light. Add an
easy showAnythingon the BOOLEAN that drives the blocker to confirm at queue time. - No partial recovery — once a path is blocked, every downstream node in that chain is skipped, period. To preserve a parallel path through the same upstream value, tee BEFORE the blocker, not after.
Null / empty / type probes
| Probe | Returns BOOLEAN when |
|---|---|
easy isNone |
Input is None / unwired / a placeholder |
ImpactIfNone |
Same, plus passes the non-None value through (combines probe + pass-through) |
easy isMaskEmpty |
All mask pixels are zero (no positive area) |
easy isFileExist |
Filesystem path resolves to a real file |
easy isSDXL |
The CLIP / pipe / model identifies as SDXL architecture |
Use cases:
- Detector pipelines:
isMaskEmpty(face_mask)→ blocker to skip detailer when no face is found. - Optional reference image:
isFileExist(ref_path)→ switch between "use reference" and "no reference" branches. - Multi-architecture workflows that need different sampler defaults:
isSDXL(pipe)→ switch sampler configuration.
Logicutils — strings, bits, regex
comfyui-logicutils is the sole source for:
- Regex / substring on strings —
LogicGateCompareString(also registered asAContainsB). Pass a regex pattern inb, a string ina, get BOOLEAN. - Bitwise integer ops — for flags packed into a single INT. Niche; mostly useful when interfacing with external systems that send flag bitmasks.
LogicGateInvertBasic— generic invert that handles any truthy/falsy input (more lenient thanImpactNeg, which expects strict BOOLEAN).
Iterator stop
ImpactConditionalStopIteration — only useful inside an Impact
detector→detailer iterator loop. Takes a BOOLEAN; when True, halts
the iterator's next round. The iterator must support stop signals
(detector-pipeline variants do; non-iterating Impact paths ignore it).
Recipes
Skip face-detailer when no face detected
LoadImage ──► BBoxDetector ──► IMAGE/MASK output
│
▼
easy isMaskEmpty ──► (BOOLEAN)
│
▼ (invert: empty → skip)
ImpactNeg
│
▼
┌───────► easy blocker ◄────── (the image+mask payload)
│ continue
▼
(downstream FaceDetailer chain, silently skipped on empty)
isMaskEmpty → True when no face found → ImpactNeg flips it → False
→ blocker fires → FaceDetailer + SaveImage chain is skipped without
error.
Multi-criteria gate
"Run the high-quality upscale path only if the image is large AND the reference exists AND we're not in SDXL mode":
GetImageSize&Count(image) ──► width ──► easy compare (> 1024) ──┐ (BOOL)
│
easy isFileExist(ref_path) ──► (BOOL) ───────────────────────────┤
│
easy isSDXL(pipe) ──► ImpactNeg (NOT SDXL) ──► (BOOL) ───────────┤
▼
ImpactLogicalOperators (AND of 3)
│
▼
ImpactConditionalBranch
tt = upscale chain
ff = passthrough
Three independent predicates combined with AND. The downstream branch is fully lazy: when any predicate is False, none of the upscale chain runs.
Distinguish "first run" from "rerun" via file existence
Useful for caching: if an output file already exists, skip regeneration.
easy isFileExist("output/cached_step1.png") ──► (BOOL)
│
▼
ImpactConditionalBranch
tt = LoadImage from cache
ff = run full pipeline + SaveImage
Gotchas
- Floats and equality:
easy comparewith==on FLOATs is a trap. UseSimpleComparison(epsilon-aware) oreasy comparewith</>instead.1.0 + 2.0 == 3.0is True, but0.1 + 0.2 == 0.3is False. - Lazy branch +
ComfyExecutionBlocker: lazy nodes (easy ifElse,ImpactConditionalBranch) won't evaluate the unselected branch, but they pass through whatever node-graph value the selected branch produces — including anExecutionBlockersentinel. If both branches can emit blockers, plan the merge carefully. SimpleMathConditionreturns FLOAT (1.0 / 0.0), not BOOLEAN. Pass throughImpactCompare(> 0.5) before feeding a switch that wants BOOLEAN.easy isNoneon a pipe: pipes (PIPE_LINE) are tuples —isNonereturns False on an empty pipe (the tuple exists, just with None fields). To detect missing pipe content, unpack withpipeOutand probe individual fields.AContainsBis regex, not substring: special characters need escaping. To do a plain substring check, escape with\Q...\Eor use Python regex-special escapes manually.
Cross-refs
comfy-flow-control— once the boolean is formed, this skill points at the switches that consume it (typed switches, ExecutionBlocker propagation, broadcast routing).comfy-math-strings— math primitives that feed comparisons (constants, sliders, SimpleMath expressions,GetImageSize&Countoutputs).comfy-debug-preview—ShowAnything/ShowTextfor inspecting the BOOLEAN being passed to a branch at queue time.
Things this skill does NOT cover
- Switching / routing AFTER the decision — that's
comfy-flow-control. - Numerical computation that doesn't yield a BOOLEAN —
arithmetic, math expressions, string formatting →
comfy-math-strings. - Image / mask manipulation upstream of the probe — getting a mask in the first place via segmentation, detection, etc. is model-inference work, not utility.
- Sampler-time conditionals — model_sampling, CFG scheduling, step gating within the diffusion loop is sampler/model territory, not workflow logic.