Nodes/jlc-comfyui-nodes/ JLC ControlNet Composition
ComfyUI Node

 JLC ControlNet Composition

Stack five ControlNets without the recursive slowdown

By Damkohler·Created 6 months ago·Updated 3 days ago· 25
 JLC ControlNet Composition
  • positive
  • negative
  • CONDITIONING
  • CONDITIONING
slot_count5
weight_011.00
weight_021.00
weight_031.00
weight_041.00
weight_051.00
weight_061.00
weight_071.00
weight_081.00
alpha1.00

Here's the problem this node exists to solve: when you chain three or four ControlNets through the normal Apply nodes, ComfyUI links them recursively. Each one wraps the last via previous_controlnet, and the sampler has to walk that whole nested tree on every step. It works, but on ControlNet-heavy Flux workflows it gets slow and VRAM-hungry, and the more conditions you stack, the worse it compounds. JLC ControlNet Composition is the pack's answer: it takes that already-built recursive chain and flattens it into one composed ControlNet that evaluates each child independently and adds the results together.

This is the original cornerstone of the JLC pack (jlc-comfyui-nodes, by J. L. Córdova / Damkohler). The pitch is a linear cost model - roughly one ControlNet's worth of work per child instead of a nested explosion - and the author's own validation shows markedly better VRAM handling on multi-ControlNet Flux runs versus native recursive chains.

How it works

You don't build anything new here. You wire your chain exactly as you normally would - ControlNet Apply nodes feeding conditioning forward, one after another - then drop JLC ControlNet Composition in front of the sampler. On execution it:

  1. Traverses the previous_controlnet chain from the conditioning, oldest to newest.
  2. Shallow-copies each child and clears its previous_controlnet, breaking the recursive linkage.
  3. Replaces the whole chain in the conditioning with one composed wrapper that computes Σ W_i · C_i(x) - each child evaluated against the same latent, then summed with your weights.

If the effective setup is exactly one ControlNet at weight 1.0, it skips the wrapper entirely and routes through a detached native single ControlNet - the mathematically equivalent fast path, so a single-control workflow costs you nothing.

The inputs that matter

  • positive / negative - your conditioning, already carrying the ControlNet chain from upstream Apply nodes. There's no image input here; the node only fuses what's already attached.
  • slot_count - how many weight rows are active, 1–8 (default 5). This clips the chain: anything upstream beyond slot_count is ignored, and weight rows above it are too.
  • weight_01weight_08 - each ControlNet's contribution. They go negative to -10, which is a real feature: negative weight on a condition pushes away from it.
  • alpha - order bias, default 1.0. Below 1 favors the earlier ControlNets in the chain, above 1 favors the later ones. The math is W_i = w_i · alpha^i, so it's a gentle positional tilt, not per-slot control.

Both outputs are CONDITIONING (positive/negative) - wire them straight into your KSampler.

Installing it

Through ComfyUI Manager, search for jlc-comfyui-nodes, or:

cd ComfyUI/custom_nodes
git clone https://github.com/Damkohler/jlc-comfyui-nodes.git

Then restart ComfyUI. This node itself pulls in no extra dependencies - no model downloads, nothing. It just reshapes what's already on your graph.

Where people get burned

The pack's own troubleshooting is blunt about the biggest trap: if your multi-ControlNet run suddenly takes far longer than expected, it's usually not these nodes. Forced --lowvram on launch caused destructive partial unload/reload cycles and a catastrophic slowdown in the author's tested Flux workflows. Run normal VRAM mode (DynamicVRAM is fine) and only reach for --lowvram if you actually need it.

Second gotcha is bookkeeping, not breakage. If slot_count doesn't match the number of ControlNets actually upstream of you, the node logs warnings - weights set with no ControlNet to apply them to, or chain members silently clipped. Enable debug logging if you're chasing a mismatch; otherwise a silent "why is my fifth weight doing nothing?" is usually just slot_count sitting at 5 while only four Apply nodes are upstream.

Categoryconditioning/controlnet

Inputs (12)

NameTypeDefaultDescription
positiveCONDITIONING
negativeCONDITIONING
slot_countoptINT51–8Number of visible/active ControlNet weight rows. Backend ignores weights above this count.
weight_01optFLOAT1.00-10–10Contribution of ControlNet 1 in extracted chain; can be negative.
weight_02optFLOAT1.00-10–10Contribution of ControlNet 2 in extracted chain; can be negative.
weight_03optFLOAT1.00-10–10Contribution of ControlNet 3 in extracted chain; can be negative.
weight_04optFLOAT1.00-10–10Contribution of ControlNet 4 in extracted chain; can be negative.
weight_05optFLOAT1.00-10–10Contribution of ControlNet 5 in extracted chain; can be negative.
weight_06optFLOAT1.00-10–10Contribution of ControlNet 6 in extracted chain; can be negative.
weight_07optFLOAT1.00-10–10Contribution of ControlNet 7 in extracted chain; can be negative.
weight_08optFLOAT1.00-10–10Contribution of ControlNet 8 in extracted chain; can be negative.
alphaoptFLOAT1.000.01–2Order bias. <1 favors earlier ControlNets, >1 favors later ones.

Outputs (2)

NameTypeDescription
CONDITIONINGCONDITIONING
CONDITIONINGCONDITIONING