toobusy Z-Image Turbo
The entire Z-Image Turbo graph, collapsed into one node
- image
- model_override
- clip_override
- vae_override
- positive_override
- negative_override
- latent_override
- zit_control
- image
- latent
- width
- height
- model
- model_clean
- clip
- vae
- positive
- negative
Z-Image Turbo is Alibaba's Apache 2.0 model that took the local photorealism default by late 2025 - it's fast on 12GB cards, and realism families like Juggernaut and epiCRealism rebuilt their lines on it. But a full Z-Image Turbo graph in vanilla ComfyUI is loaders plus LoRA plus text-encode plus sampler plus decode, strung across half the canvas. toobusy Z-Image Turbo folds all of that into one node: model, CLIP and VAE loaders, up to five LoRA slots, conditioning, sampling, and decoding, with the whole chain inside.
The README's before/after table says it plainly: "UNET/CLIP/VAE loader + LoRA + encoding + sampler + decode → 1 node." And because it's a fold rather than a wrapper around an API, every sub-piece is still accessible - the node passes the loaded model, clip, vae, and the final positive/negative conditioning out of its outputs so you can reuse them downstream without re-loading anything.
How it works, and the inputs that matter
Model auto-detection: since v0.2.10 the node does a fuzzy filename scan of your model folders, so it usually finds the right Z-Image diffusion model, lumina2 text encoder, and VAE on its own. If it grabs the wrong file, set model_name / clip_name / vae_name explicitly. The default VAE is FLUX1/ae.safetensors - that's not a mistake, Z-Image shares Flux's VAE.
The three fields you'll touch most:
positive/negative- plain text; the node encodes them with the internal lumina2 CLIP.ratio_preset+megapixels- the resolution system,2:3at 1MP by default. Set bothwidthandheightto positive values to override.steps,cfg,denoise- the sampling knobs. Defaults are 8 steps, cfg 1, denoise 1. Z-Image's LoRA-stacking ceiling is real (about two LoRAs at strength ≤1.4 before things melt), so don't expect to pile on five at full strength and keep the photorealism.
The outputs are the story
Beyond image, it exposes latent, width, height, and - the point for power users - model, model_clean, clip, vae, positive, negative. That's the whole pipeline out for the picking. The README's recommended hires loop is:
Z-Image Turbo -> toobusy Hires Upscale -> Z-Image Turbo (latent_override)
Where people get burned: model vs model_clean. If you're continuing at the same resolution and same control conditions, model is fine. If you're doing a second pass at a different resolution or swapping LoRAs, use model_clean - the README calls it "safer" and it is. Also note latent_override beats both the image input and the empty latent when connected.
Connect an image and the node switches to img2img (VAE-encoded start latent, denoise becomes change strength). Connect a zit_control from toobusy ZIT ControlNet and you get depth/canny/pose control. Leave both unconnected and it's plain text-to-image. That tri-mode behavior is why this node collapses a whole graph - it's not a button, it's a pipeline with the plumbing exposed.
Installing it
cd ComfyUI/custom_nodes
git clone https://github.com/nicekriss/toobusy.git toobusy
or search "toobusy" in ComfyUI Manager, then restart and hard-refresh. You supply the model files yourself: ZIT/zImage_turbo.safetensors, the lumina2 text encoder, and the Flux VAE in your model folders. The example workflow is docs/workflows/z_image_turbo.json.
If you already have a working Z-Image Turbo graph you love, this node is optional - you're not gaining quality, you're gaining a shorter canvas and a reusable one-node pipeline. If you're setting up Z-Image from scratch, it removes most of the setup pain in one drop.
Inputs (42)
| Name | Type | Default | Description |
|---|---|---|---|
| model_name | COMBO | ZIT/zImage_turbo.safetensors | 1 options: ZIT/zImage_turbo.safetensors |
| clip_name | COMBO | ZIT/zImage_textEncoder.safetensors | 1 options: ZIT/zImage_textEncoder.safetensors |
| vae_name | COMBO | FLUX1/ae.safetensors | 1 options: FLUX1/ae.safetensors |
| positive | STRING | — | |
| negative | STRING | — | |
| ratio_preset | COMBO | 2:3 | 9 options: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, +3 |
| megapixels | FLOAT | 1.000.1–4 | — |
| divisible_by | INT | 328–128 | — |
| batch_size | INT | 11–64 | — |
| seed | INT | 10–18446744073709550000 | — |
| steps | INT | 81–100 | — |
| cfg | FLOAT | 1.00–30 | — |
| sampler_name | COMBO | res_multistep | 44 options: euler, euler_cfg_pp, euler_ancestral, euler_ancestral_cfg_pp, heun, heunpp2, +38 |
| scheduler | COMBO | simple | 9 options: simple, sgm_uniform, karras, exponential, ddim_uniform, beta, +3 |
| denoise | FLOAT | 1.000–1 | — |
| aura_shift | FLOAT | 3.00–20 | — |
| lora_slots | INT | 00–5 | — |
| lora_1_enable | BOOLEAN | false | — |
| lora_1_name | COMBO | Lora/ZIT/ZIT_Neobabae_v1.safetensors | 2 options: None, Lora/ZIT/ZIT_Neobabae_v1.safetensors |
| lora_1_strength | FLOAT | 1.00-10–10 | — |
| lora_2_enable | BOOLEAN | false | — |
| lora_2_name | COMBO | None | 2 options: None, Lora/ZIT/ZIT_Neobabae_v1.safetensors |
| lora_2_strength | FLOAT | 1.00-10–10 | — |
| lora_3_enable | BOOLEAN | false | — |
| lora_3_name | COMBO | None | 2 options: None, Lora/ZIT/ZIT_Neobabae_v1.safetensors |
| lora_3_strength | FLOAT | 1.00-10–10 | — |
| lora_4_enable | BOOLEAN | false | — |
| lora_4_name | COMBO | None | 2 options: None, Lora/ZIT/ZIT_Neobabae_v1.safetensors |
| lora_4_strength | FLOAT | 1.00-10–10 | — |
| lora_5_enable | BOOLEAN | false | — |
| lora_5_name | COMBO | None | 2 options: None, Lora/ZIT/ZIT_Neobabae_v1.safetensors |
| lora_5_strength | FLOAT | 1.00-10–10 | — |
| imageopt | IMAGE | Connect an image to switch this node to img2img. The image is VAE-encoded as the starting latent and 'denoise' becomes the change strength (lower = closer to the source). Leave unconnected for plain text-to-image. | |
| widthopt | INT | 00–8192 | 0 = use ratio_preset + megapixels. Set width AND height > 0 to enter the resolution directly (rounded to divisible_by). In img2img this scales the source image to the given size. |
| heightopt | INT | 00–8192 | 0 = use ratio_preset + megapixels. Set width AND height > 0 to enter the resolution directly (rounded to divisible_by). In img2img this scales the source image to the given size. |
| model_overrideopt | MODEL | — | |
| clip_overrideopt | CLIP | — | |
| vae_overrideopt | VAE | — | |
| positive_overrideopt | CONDITIONING | External positive conditioning. Connected = the positive prompt text is ignored (and the internal CLIP is not even loaded when both overrides are connected and no LoRA is active). | |
| negative_overrideopt | CONDITIONING | External negative conditioning. Connected = the negative prompt text is ignored. | |
| latent_overrideopt | LATENT | External starting latent (e.g. from toobusy Hires Upscale). Connected = wins over the image input and the empty latent; 'denoise' is the change strength. Width/height follow the latent. | |
| zit_controlopt | ZIT_CONTROL | Connect a 'toobusy ZIT ControlNet' module to apply depth/canny/pose Fun-ControlNet-Union model patches. Leave unconnected for plain generation. |
Outputs (10)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |
| latent | LATENT | — |
| width | INT | — |
| height | INT | — |
| model | MODEL | — |
| model_clean | MODEL | — |
| clip | CLIP | — |
| vae | VAE | — |
| positive | CONDITIONING | — |
| negative | CONDITIONING | — |