ComfyUi-DuoNodes
Standalone ComfyUI custom nodes for stacking multiple LoRAs in a single, dynamic node — including an orthogonal stacking mode that reduces interference between LoRAs.
ComfyUi-DuoNodes
Standalone ComfyUI custom nodes for stacking multiple LoRAs in a single, dynamic node — including an orthogonal stacking mode that reduces interference between LoRAs.
No dependencies. Drop it in custom_nodes/ and go.
Nodes
| Node | Inputs / Outputs | Stacking | |------|------------------|----------| | Multi LoRA Stack | MODEL + CLIP | Sequential (additive) | | Multi LoRA Stack (Model Only) | MODEL | Sequential (additive) | | Multi LoRA Stack Ortho (Model Only) | MODEL | Sequential or Gram-Schmidt orthogonalized |
All three live in the loaders category and share the same dynamic interface:
- ➕ Add LoRA — add as many LoRA slots as you need
- Per-slot enable toggle, LoRA dropdown, and strength slider (-2.0 to +2.0)
- Toggle All LoRAs on/off at once
strength_1…strength_10optional inputs — wire a FLOAT into any slot's strength to drive it from another node (scheduler, primitive, etc.). A connected input overrides that slot's slider.
Orthogonal stacking (ortho_gs)
When two LoRAs are stacked additively, ΔW = s₁·(A₁B₁) + s₂·(A₂B₂). If their down
matrices (B) read from overlapping input directions, the LoRAs interfere — partially
cancelling or amplifying each other unpredictably. This is why stacking two character
or style LoRAs often muddies both.
The Ortho node's ortho_gs mode applies Gram-Schmidt orthogonalization in input
space at load time:
- The first LoRA's down matrix is kept as-is; its row space is committed as a basis.
- Each subsequent LoRA's down matrix has its rows projected onto the orthogonal complement of all previously committed row spaces.
- The basis is extended and the process repeats down the stack.
Each LoRA ends up reading from input directions the earlier LoRAs ignore, eliminating the interference term. Up matrices, alphas, and strength scaling are untouched.
Behavior notes:
- Order matters. The first LoRA in the stack is unmodified; later LoRAs give way. Put your most important LoRA first.
- The effect is most visible when stacking LoRAs with similar subjects or styles. LoRAs targeting unrelated features look nearly identical to sequential.
- Later LoRAs can lose magnitude when their intended subspace is already covered by an earlier LoRA — that's the tradeoff for removing interference.
merge_method = sequentialon the Ortho node reproduces the plain node exactly, so you can A/B the two modes in place.- If ComfyUI internals change and patch extraction fails, the node falls back to sequential stacking rather than erroring.
Installation
cd ComfyUI/custom_nodes/
git clone https://github.com/UndefinedUo/ComfyUi-DuoNodes.git
Restart ComfyUI. The nodes appear under loaders.
LoRA stack format
Configurations are stored as JSON in the node's lora_stack widget (managed by the
UI — you normally never edit it by hand):
[
{ "on": true, "lora": "flux/style_lora.safetensors", "strength": 1.0 },
{ "on": false, "lora": "character_lora.safetensors", "strength": 0.8 }
]
File structure
ComfyUi-DuoNodes/
├── __init__.py # Node registration
├── multi_lora_stack.py # All three node classes
└── web/
├── multi_lora_stack.js # Full version UI
├── multi_lora_stack_model_only.js # Model-only UI
└── multi_lora_stack_model_only_ortho.js # Ortho node UI
Troubleshooting
- Nodes don't appear — check the ComfyUI console for import errors and restart ComfyUI completely.
- LoRA dropdown empty — verify LoRAs exist in
models/loras/and load with the standard LoRA Loader. - UI looks wrong after update — hard-refresh the browser (Ctrl+F5) to clear cached JS.
- Ortho mode seems to do nothing — check the console for the
ortho keys: N, pass-through: Mline. If everything is passing through, the stacked LoRAs don't share model keys and there's nothing to orthogonalize.
License
MIT — see LICENSE.