Merge LoRAs to File (rholdorf)
Bake two LoRAs into one file — exactly, not approximately
- path
- retained_energy
You've got two LoRAs you reach for together every single time - a character LoRA at 0.7 and a style LoRA at 0.4, say. Loading both works fine, but you're tired of the extra loader, you want one file to share, or you just want to know what the combination looks like with the strengths frozen in. People have been merging LoRAs since 2024 and the ask hasn't gone away.
Merge LoRAs to File (rholdorf) is the clean answer to that. It bakes two standard LoRAs into a single .safetensors, and here's the part that separates it from the herd: it's an exact merge, not an approximation.
Why "exact" matters
Most LoRA merge tools average the weight matrices. That's a blend - it produces a third thing that sort of sits between your two LoRAs, usually mushier than either. This node does the opposite: it reproduces exactly what applying both in sequence does, à la rgthree's Power Lora Loader. Because [Up_A | Up_B] @ [Down_A ; Down_B] == Up_A@Down_A + Up_B@Down_B, concatenating the up matrices along the rank dimension (with each LoRA's strength and alpha/rank scale folded into the up side) and the down matrices along rank gives you the precise weighted sum of both deltas. No SVD, no loss, no guesswork. The ranks don't even have to match - a rank-32 and a rank-64 merge into a rank-96 file.
The output alpha is set equal to the merged rank, so ComfyUI's load-time alpha/rank scale lands at exactly 1.0. That's the one rule that matters: load the merged file at strength 1.0. If you bake at 0.7 and 0.4 and then load the merged file at 0.5, you get half of both - not your original combination.
What you set
lora_name1/lora_name2- dropdowns populated from yourlorasfolder.strength1/strength2(default 0.5 each) - the strengths baked in. Read those tooltips: it's the value you'd set in Power Lora Loader.filename_prefix(defaultmerged_lora) - output name relative to the loras folder;.safetensorsis appended for you.target_rank(optional, default 0) - 0 keeps the exact merge. A positive value recompresses the merged delta down to that rank via truncated SVD (Eckart–Young optimal), which makes a smaller file at the cost of exactness. Say you merge a 32 and a 64 and don't want a rank-96 file eating space: recompress to 64 and checkretained_energy.
Outputs: path (the relative path of the saved file) and retained_energy. It's an output node, so it saves the file and prints a summary - plus the retained-energy percentage on the node face after a run. Exact merge shows 100% (exact); a recompressed one shows something like 96.4%, which is your quality signal. If that number drops below the high nineties, you've compressed too far for the merge to be worth it.
What it refuses
Standard LoRA lora_up / lora_down (+ alpha), plus the other up/down naming schemes ComfyUI recognises and direct .diff / .diff_b deltas - those all work. LoHa, LoKr, OFT, DoRA and LoCon-mid files get a hard error rather than a wrong output, because none of those is a plain up @ down product. It also raises on a shape mismatch between the two LoRAs, which is its way of telling you the LoRAs don't target the same base model. Don't fight it - that's the node being honest.
Install
Same pack as the rest of the rholdorf nodes:
cd ComfyUI/custom_nodes
git clone https://github.com/rholdorf/comfyui_imgtools
Restart ComfyUI. No dependencies beyond what ComfyUI already ships (torch, numpy, Pillow), no model downloads. The merged file lands in your loras folder, so it shows up in any LoraLoader's dropdown - refresh if it doesn't appear immediately.
When it's actually worth it
If your combination is truly fixed - same two LoRAs, same strengths, every generation - baking is a real win: one loader, one file to share, marginally less work per run. If you're constantly nudging strengths between 0.3 and 0.7, keep the two loaders and skip the merge; the whole point is freezing a combination, and a merged file is awkward to re-blend. The niche that makes it shine is sharing and portability - one file instead of "install these two, then set these exact strengths."
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| lora_name1 | COMBO | First LoRA to combine. | |
| strength1 | FLOAT | 0.50-100–100 | Strength baked in for the first LoRA (the value you'd set in Power Lora Loader). |
| lora_name2 | COMBO | Second LoRA to combine. | |
| strength2 | FLOAT | 0.50-100–100 | Strength baked in for the second LoRA. |
| filename_prefix | STRING | merged_lora | Output name (relative to the loras folder). '.safetensors' is added automatically. |
| target_rankopt | INT | 00–4096 | 0 = exact rank concatenation (rank = sum of both). A positive value recompresses the merged delta to that rank via truncated SVD (smaller file, approximate). E.g. 64 to match a rank-64 LoRA. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| path | STRING | — |
| retained_energy | STRING | — |