Power LoRA Merger
Bake several LoRAs into one file instead of stacking loaders
- model
- clip
- options
- model
- clip
- lora_path
If you've ever chained four LoraLoader nodes to combine a character LoRA with a style LoRA and a couple of detail-boost LoRAs, you already know the annoyance: every run reloads and reapplies all four, and sharing the workflow means sharing four separate files. WAS Power LoRA Merger merges them once into a single .safetensors you can drop into models/loras and load normally from then on - with a choice of real merge strategies, not just a naive average.
The "Power" in the name isn't an accident - it's the same convention rgthree uses for its Power Lora Loader, and it means the same thing here: the LoRA files you're actually merging aren't separate graph inputs. You add them through the node's own on-node UI. If you're staring at this node hunting for lora_1/lora_2 sockets to wire up, that's why you won't find them.
How it works
You pick a mode, optionally tune it further with a WAS Power LoRA Merger Options node (its own article - plug it into the optional options input), and the merger writes the result to models/loras. If you also wire in a model and clip, it applies the freshly-merged LoRA to them immediately, so the merge and the apply happen in one run instead of needing a separate LoraLoader afterward.
The modes, per the node's own tooltip:
svd(default) - recompress the merged delta via SVD. The general-purpose choice.rebase- SVD-recompress a single LoRA on its own.add- exact linear stacking, no compression.add-diff- start from a base LoRA and add weighted diffs toward the others.add-orth- same idea, but orthogonalizes the contributions so they don't cancel each other out.diff-export- exports only the difference between the first two, useful for extracting what one LoRA added on top of another.moe- routes each module through a mixture-of-experts gate across your source LoRAs.obfuscate- a stack-equivalent factor rebasis that skips SVD.block-mix- routes specific modules to LoRA A or B by ablock_mix_recipe, then merges via stack or SVD.
SVD-based LoRA merging isn't new - Kohya's GUI has shipped a "Merge LoRA (SVD)" option for a while, valued because it copes better with mismatched ranks and architectures than a straight stack. This node brings that idea, plus several other strategies, natively into ComfyUI.
block_mix_recipe only matters in block-mix mode: the default concept_a_style_b keeps concept/attention blocks from LoRA A and style/feed-forward blocks from B, with mirror-image and image/text-stream variants for different architectures.
The inputs and outputs that matter
mode/block_mix_recipe- the strategy, as above.output_filename(defaultmerged_lora.safetensors) - relative tomodels/loras;.safetensorsgets appended if you leave it off.output_model_strength/output_clip_strength(default 1) - only relevant if you wired inmodel/clip; how hard the new LoRA gets applied to those pass-throughs.- Optional
model/clip- apply the merge result to these immediately. - Optional
options- aWAS_LORA_MERGE_OPTIONSfrom the companion Options node.
Outputs: model, clip (pass-through, patched if you wired inputs in), and lora_path (STRING) - where it landed, worth routing into a text/preview node to confirm the merge succeeded before you go hunting through models/loras.
How to install it
Via ComfyUI Manager: search WAS_Extras, install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/WAS_Extras
Restart ComfyUI. No extra dependencies for this node specifically.
Common issues & troubleshooting
Merged result barely resembles either source LoRA. SVD-family modes are lossy compression by nature - a low rank or an aggressive auto_rank_threshold on the Options node throws away real signal. Raise the rank before assuming the algorithm is broken.
Picked moe or block-mix and it made things worse. Those modes are aimed at combining LoRAs that specialize in genuinely different things - identity from one, style from another. For merging near-duplicate training runs of the same subject, add or the default svd is the saner starting point.
Strength sliders don't seem to do anything. output_model_strength/output_clip_strength only matter if model/clip are actually wired in. If you're just here to bake a .safetensors and load it later with a normal LoraLoader, leave those inputs disconnected and ignore the sliders.
Inputs (86)
| Name | Type | Default | Description |
|---|---|---|---|
| output_filename | STRING | merged_lora.safetensors | Name to save the merged LoRA under, inside your LoRA folder. Sub-folders are allowed, for example 'styles/mixed.safetensors'. '.safetensors' is added when it is missing, and the name cannot step outside the LoRA folder. |
| output_model_strength | FLOAT | 1.000–100 | How strongly the merged LoRA is applied to the model output, if a model is connected. 1.0 is full strength, 0.5 is half. This does not change the saved file, only what comes out of the model socket. |
| output_clip_strength | FLOAT | 1.000–100 | The same for the clip output: how strongly the merged LoRA is applied to the connected clip. Lower it when a LoRA's trigger words are overwhelming the rest of the prompt. |
| mode | COMBO | svd | How the LoRAs are combined. `svd` recompresses the combined result back to one rank, which keeps the file small and is the usual choice. |
| block_mix_recipe | COMBO | concept_a_style_b | Only read in `block-mix` mode: which of the two LoRAs each part of the model comes from. `all_a` and `all_b` route everything one way. |
| modelopt | MODEL | Optional. A model to apply the merged LoRA to once it is saved, so the merge can be tested in the same run. Leave it unconnected to only write the file. | |
| clipopt | CLIP | Optional, and only used when a model is connected too: the clip the merged LoRA's text-encoder half is applied to. | |
| optionsopt | WAS_LORA_MERGE_OPTIONS | Optional settings from a Power LoRA Merger Options node: rank, precision, module filters and the per-mode controls. Leave it unconnected to merge at rank 32 in bf16. | |
| lora_1_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_1opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_1_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_2_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_2opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_2_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_3_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_3opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_3_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_4_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_4opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_4_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_5_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_5opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_5_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_6_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_6opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_6_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_7_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_7opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_7_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_8_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_8opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_8_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_9_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_9opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_9_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_10_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_10opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_10_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_11_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_11opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_11_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_12_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_12opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_12_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_13_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_13opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_13_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_14_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_14opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_14_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_15_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_15opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_15_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_16_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_16opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_16_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_17_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_17opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_17_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_18_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_18opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_18_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_19_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_19opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_19_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_20_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_20opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_20_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_21_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_21opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_21_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_22_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_22opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_22_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_23_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_23opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_23_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_24_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_24opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_24_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_25_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_25opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_25_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
| lora_26_enabledopt | BOOLEAN | true | Whether this row takes part. `true` applies it; `false` mutes it and keeps the file and the strength it was set to, so neither is typed again to bring it back. |
| lora_26opt | COMBO | None | LoRA file this row uses. `None` leaves the row empty, which counts the same as switching it off. |
| lora_26_weightopt | FLOAT | 1.00-10–10 | How strongly this row counts. 1.0 is the LoRA as it was trained, below 1 weakens it, above 1 pushes it past what it was trained for, and a negative value applies it in reverse. 0 leaves the row out. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| model | MODEL | The connected model with the merged LoRA applied, or nothing when no model was connected. |
| clip | CLIP | The connected clip with the merged LoRA applied, or nothing when no model and clip were connected. |
| lora_path | STRING | The saved file's name relative to your LoRA folder, such as 'styles/mixed.safetensors'. Feed it to a loader, or to a text node to record what a run produced. |