Lodestone Merge LoRAs (2)
When two LoRAs fight, merge the weight deltas instead of stacking them
- output_filename
Stacking two LoRAs in ComfyUI works right up until it doesn't. Two different character LoRAs at 0.6 each bleed into each other, a style LoRA and a detail LoRA that both touch the same blocks over-fire the weights they share, and every render costs you two LoRA passes. This node takes the other road: it expands two LoRAs into their real per-layer weight changes, merges those, and saves one new LoRA file that does the job of both.
It ships in the "Model Utility Toolkit" pack (silveroxides/ComfyUI-ModelUtils), a collection of offline model surgery tools - MetaKeys, PruneKeys, checkpoint mergers, LoRA extraction. The Lodestone family is its straightforward full-delta merger, and this two-input node is the one you'll actually reach for most days.
Why merge deltas instead of factors?
A LoRA stores a low-rank pair of matrices (down/up) that approximates a full weight change: the real effect is roughly up @ down. Most "LoRA merging" averages those compressed factors, which is like averaging two lossy JPEGs and hoping the artifacts cancel. Lodestone does the opposite - it materializes each LoRA's actual per-layer weight delta, one layer at a time, and combines those dense tensors. Merging two 128-rank LoRAs by their real effects handles the overlap honestly, and what you get out is a single full-difference .diff LoRA with alpha already normalized out of the picture.
There's no free lunch: the math is a dense matrix product per layer, so it's heavier than a factor blend, and the output is a full-size dense LoRA rather than a tiny rank-128 file. That's the point - you bake once, then the single file rides through the pack's own LoRA tooling (which reads these canonical full-difference files natively), or gets stamped into a checkpoint via LoRAMergeToModel.
What you actually set
lora_1/lora_2- dropdowns of everything in yourmodels/lorasfolder.lora_1is the anchor: it supplies the metadata and defines the output layer set.calc_mode(defaultsum) - how the expanded deltas combine per layer.sumadds them;meandivides by the contributor count. The interesting ones are the Frobenius-norm-aware modes:slotnormscales each input's delta to the median magnitude before averaging,normmatchadds the deltas then rescales the result back to a typical input's magnitude, andslotnorm-normmatchdoes both. If one LoRA is much "louder" than the other, plainsumdouble-counts its effect - that's the case the norm modes exist for. Start withsum, and if the merged result is over- or under-strong, that's your dial.mismatch_mode(defaultskip) - what happens whenlora_1has a layer the other file lacks:skipkeeps LoRA 1's layer untouched,zerostreats the missing input as a zero update,erroraborts rather than guess.output_filename- the name, without extension, of the.safetensorswritten to your loras folder.save_dtype(defaultbf16) andprocess_device(defaultcuda) - precision and where the per-layer math runs. If a layer blows past your VRAM, it's retried on CPU automatically.
Less commonly: exclude_patterns copies matching layers straight from LoRA 1 instead of merging them (regex per line unless you flip glob_patterns), and discard_patterns drops matching layers from the output entirely.
The only output is output_filename - this is a terminal node. Its job is producing a file, not passing a model downstream.
How it's built, and what can bite you
The node streams one logical layer at a time (via the pack's unified-efficient-loader dependency) and writes each completed delta incrementally, so memory stays near a single layer's size regardless of LoRA count. The destination file is only replaced once the whole merge finishes - a crash mid-run won't leave you a half-written LoRA. The metadata on the file records merge_method: lodestone:<calc_mode>, which is handy later when you've forgotten what you mixed.
The honest gotchas:
- It expects canonical LoRA factor pairs. DoRA magnitude vectors (
dora_scale), low-bit/quantized factors, and exotic layer shapes make it raise rather than produce garbage - feed it plain LoRAs. - Both LoRAs need matching layer keys. Layers present in only one file are exactly what
mismatch_modeis for. - Same-name runs overwrite the previous output file. Give merges distinct
output_filenames unless you mean to replace them.
Installing it
ComfyUI Manager is the easy path - search for Model Utility Toolkit (the pack's display name) and install. Manually, from a terminal next to ComfyUI:
cd ComfyUI/custom_nodes
git clone https://github.com/silveroxides/ComfyUI-ModelUtils
Then restart ComfyUI. No API key, no model downloads - these nodes only read LoRAs you already own, and Manager or the pack's requirements.txt pulls in its streaming dependency (unifiedefficientloader). Find the node under ModelUtils → LoRA → Merge → Lodestone in the picker, or just search "Lodestone". You'll see its 2, 3, and Multi variants; this two-input one is the same machinery with fewer slots to fill. If you need a third input, grab Lodestone Merge LoRAs (3) - or the Multi node, which handles up to eight equal-strength LoRAs.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| lora_1 | COMBO | First LoRA to merge. It also supplies metadata and is the layer kept when Missing Layer Handling is set to skip. | |
| lora_2 | COMBO | Second LoRA to merge. It contributes equally with LoRA 1 wherever both contain the same layer. | |
| calc_mode | COMBO | sum | How full LoRA weight changes are combined per layer. sum adds them; mean averages them; slotnorm equalizes each input's Frobenius magnitude before averaging; normmatch adds them and scales the result to a typical input magnitude; slotnorm-normmatch performs both normalization steps. |
| mismatch_mode | COMBO | skip | What to do when a layer exists in LoRA 1 but is absent from another input. skip copies LoRA 1's layer unchanged; zeros treats each missing input as a zero update; error stops without replacing an existing output file. |
| output_filename | STRING | lodestone_merged_2_lora | Name of the new .safetensors file. It is saved in ComfyUI's loras folder; omit the extension. |
| save_dtype | COMBO | bf16 | Precision used to save the expanded full-weight difference tensors. FP32 is largest and most precise; FP16 is smallest; BF16 has wider numeric range than FP16. |
| process_device | COMBO | cuda | Where each full layer is expanded and merged. CUDA is faster; if a layer runs out of VRAM, that layer is automatically retried on CPU. |
| exclude_patterns | STRING | Optional layer-name patterns to copy from LoRA 1 instead of merging. Enter one pattern per line; useful for protecting specific blocks. | |
| discard_patterns | STRING | Optional layer-name patterns to leave out of the saved LoRA completely. Enter one pattern per line; discarded layers cannot affect the model. | |
| glob_patterns | BOOLEAN | false | Choose filter syntax. Off uses regular expressions; on uses shell-style globs where * matches any text and ? matches one character. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| output_filename | * | — |