Z-Image Universal LoRA Loader
The LoRA loader that bakes instead of patching
- RAW_MODEL
- RAW_CLIP
If you were around for the first weeks of Z-Image, you remember the LoRA loader console errors. This node is the shrug that fixes them. Z-Image Universal LoRA Loader doesn't apply a LoRA the way ComfyUI normally does - it bakes it. It reads your transformer and text encoder as raw state dicts, adds the LoRA's weight delta straight into the tensors, and hands back RAW_MODEL and RAW_CLIP that already contain the LoRA. No runtime patcher, no MODEL/CLIP objects, no second chances: the LoRA is in the weights.
That's a different philosophy from the LoraLoaderModelOnly you're used to, and it's the front half of Zlycoris's raw-patching pipeline. Load and fuse here, then pipe the outputs into Z-Image Save Transformer (or one of the pack's merge nodes) to write the result as a checkpoint. Set lora_name to "None" and it even doubles as a plain raw loader, returning the unpatched model and encoder.
Why "universal"? Because it matches keys by normalization instead of exact names. Strict loaders need the file's keys to line up with the model's; this one strips prefixes, folds to_q/to_k/to_v into a fused qkv, tolerates trainer-specific naming, and slices QKV-fused attention weights when shapes don't line up. Files a strict loader rejects often just work here. Fair warning: the README bills it as covering the whole LyCORIS family, but the code itself handles standard lora_A/lora_B and lora_up/lora_down layouts with optional alpha - the heavy LoHa/LoKr factorized math lives in the pack's other loader. The magic here is tolerant matching, not full factorization.
Inputs:
transformer_name: dropdown of yourdiffusion_modelsfolder (or "None").text_encoder_name: dropdown oftext_encoders(for Z-Image, that's Qwen3-4B).lora_name: dropdown of yourlorasfolder.strength_model(FLOAT, default 1.0, −100…100): how hard to bake into the transformer.strength_clip(FLOAT, default 1.0): same, for the text encoder.
Two things about strength. It multiplies the LoRA's own alpha/rank scaling, so 1.0 means "as intended." And the range goes negative - handy for subtracting a LoRA's effect. But because this is a bake, not a patch, you can't dial it live afterward; to adjust, you re-run the chain. Set a strength to 0 (or leave one encoder unselected) to skip that side entirely.
Troubleshooting: the node logs to z_image_universal.log in your ComfyUI folder and prints a "Total Patched: N" line. If N is 0, the key matcher didn't recognize the file - the LoRA silently didn't apply, and what you get out is just the raw model. Also note it reads from the ComfyUI standard folders (diffusion_models, text_encoders, loras), and it expects safetensors; GGUF files won't show in these dropdowns.
Install: ComfyUI Manager (search "ComfyUI-Zlycoris") or cd ComfyUI/custom_nodes && git clone https://github.com/TripleHeadedMonkey/ComfyUI-Zlycoris.git, then restart. No model downloads. The pack ships a big requirements.txt (transformers, diffusers, gguf, lycoris…), though this loader itself only touches torch and safetensors. It's a niche tool for people who'd rather own a baked LoRA than babysit a patch - and once you've baked one, you'll see why they do.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| transformer_name | COMBO | 1 options: None | |
| text_encoder_name | COMBO | 1 options: None | |
| lora_name | COMBO | 1 options: None | |
| strength_model | FLOAT | 1.00-100–100 | — |
| strength_clip | FLOAT | 1.00-100–100 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| RAW_MODEL | RAW_MODEL | — |
| RAW_CLIP | RAW_CLIP | — |