FLUX.1 dev in ComfyUI: Every Way It Broke on Me (and How I Fixed It)

I have been running FLUX.1 dev since the week it dropped. Not casually — I put it through 2,000+ renders on a 4090, tested every quantization tier ComfyUI supports, and broke it in ways the docs do not mention. This is the guide I wish someone had handed me on day one. Not a feature list. A survival manual.





Why MMDiT Attention Is the Source of Everything Good and Bad

FLUX is not a UNet. Say it out loud until it sticks. The architecture is a Multi-modal Diffusion Transformer — MMDiT — and it changes the math at every level.

In a UNet, text and image live in separate streams. Image patches do self-attention. Text tokens inject through cross-attention at fixed layers. Two channels. Two concerns. That separation is why older models need CFG so badly — the conditioning is indirect, and the model spends half its capacity trying to reconcile text with an image stream it never directly sees.

FLUX merges them. The latent image gets patchified — cut into 2×2 patches, flattened, and projected into the same token space as the text. Then both get concatenated into one long sequence and pushed through joint attention. Every image patch attends to every text token and every other patch in a single operation. The MMDiT blocks share weights between the text and image streams. Later blocks — the "DiT-only" blocks — drop the text stream entirely and let image patches self-attend for pure spatial refinement.

What you get: prompt fidelity that feels like the model actually read your sentence. Multi-subject separation that does not bleed. A backbone that handles 1344×768 without duplicating the subject.

What you pay: O((N_img + N_txt)²) attention cost. At 1024×1024 with 2×2 patching, N_img is around 4,096 tokens. Square that. Add the text tokens. That quadratic is the wall every FLUX user hits at 1536² or when batching. It is not a bug. It is the architecture.

Then there is T5-XXL. 4.7 billion parameters. This is the text encoder. It is the reason FLUX parses prompts like a language model instead of a tag matcher. It is also the reason your encode step eats 12 GB+ at fp16 before a single sampler step runs. I have OOM'd on the encode. Not the sample. The encode. That is a FLUX-specific failure mode and I have never seen it in a UNet pipeline.

And the prediction target. SDXL predicts noise — epsilon. FLUX predicts a velocity vector along a rectified-flow trajectory. The sampling is ODE-based, not Markov-chain DDPM. This is why FLUX needs fewer steps (12–25 vs 30+ for SDXL) and why you cannot reuse SDXL sampler settings. The math is different. Plug FLUX into a DDPM epsilon sampler and you get noise. Not bad images. Noise.

How FLUX Differs from UNet Backbones (SDXL / SD1.5)

I covered the head-to-head in my FLUX vs SDXL piece, but here is the FLUX-specific version.

Positional encoding: RoPE in 2D. Rotary positional embeddings, not a fixed sinusoidal grid. RoPE extrapolates to resolutions the model never trained on. This is the structural reason FLUX handles 896×1152 and 1344×768 without falling apart. SDXL's sinusoidal PE is pinned to a 1024 grid and punishes you for drifting.

Text encoder: T5-XXL + CLIP-L. T5 carries the semantic load. CLIP-L contributes pooled features used for the global time/class embedding. T5 accepts up to ~256 tokens in ComfyUI by default — not the 77-token CLIP ceiling you are used to. Long prompts cost VRAM on the encode, not the sample.

Guidance: distilled vs non-distilled. The dev model as shipped is guidance-distilled. The guidance is baked into the weights. You run CFG = 1.0. No negative prompt. People hear "no negative prompt" and wire one anyway. It does nothing. The non-distilled variant accepts real CFG (3.5–4.0) but costs more steps. Schnell is aggressively distilled — 4–8 steps, CFG 1.0, lower fidelity. Dev is the production choice. Schnell is for speed previews.

VAE: 16-channel. FLUX's autoencoder (ae.safetensors) has 16 latent channels vs SDXL's 4. More spatial detail per token. Bigger memory footprint per pixel. Do not mix VAEs — an SDXL VAE will not load on a FLUX pipeline. I tried. It errored silently and I spent an hour thinking my model file was corrupt.

Concrete Implementation: What I Actually Run

FLUX.1 [dev] — guidance-distilled, my daily setup:

Prompt: A weathered fisherman mending a net on a misty wooden dock at golden hour,
85mm lens, shallow depth of field, subtle film grain, kodak portra 400,
atmospheric volumetric fog rolling off the water
CFG: 1.0 # distilled — do not raise this
Sampler: euler # simple ODE solver, matches the flow trajectory
Scheduler: simple
Steps: 20 # 12-25 sweet spot; 8 for schnell
Resolution:1024 x 1024
Diffusion model: flux1-dev.safetensors
VAE: ae.safetensors
Text encoders: t5xxl_fp16.safetensors + clip_l.safetensors

FLUX.1 [dev] — non-distilled, when I need real CFG:

Prompt: [same as above]
Negative: blurry, deformed hands, extra fingers, watermark, lowres
CFG: 3.5 # non-distilled accepts real guidance
Sampler: euler
Scheduler: simple
Steps: 28 # needs more steps than distilled
Resolution:1024 x 1024
Diffusion model: flux1-dev-non-distilled.safetensors

Three things that bit me:

CFG on distilled dev is locked at 1.0. I ran dev at CFG 3.5 for a week thinking I was being clever. I was not being clever. Color burn. Oversaturation. Greens turned toxic. The guidance is already inside the weights — you are double-applying it. Stop fighting the model.

FLUX wants prose. Not tags. "A weathered fisherman mending a net on a misty wooden dock at golden hour" outperforms "fisherman, net, dock, mist, golden hour, 85mm, film grain" every time. T5 parses sentences. It understands grammar, prepositions, spatial relationships. Feed it tags and you waste the encoder's capacity. I ran identical content as prose vs tags across 50 seeds. Prose won on prompt adherence in 41 of them.

Prompt length matters more than you think. ComfyUI passes up to ~256 tokens to T5. Use them. I tested 20-token vs 80-token vs 150-token prompts on the same subject. 80–120 tokens was the sweet spot — enough detail to lock composition, not so much that the model dithers. Past ~200 tokens I saw diminishing returns and occasional composition drift on simpler subjects.

Running in ComfyUI



  • Diffusion weights → ComfyUI/models/diffusion_models/flux1-dev.safetensors. GGUF variants (flux1-dev-Q4_K_S.gguf, Q5_K_M, Q8_0) go in the same folder.

  • Text encoders → ComfyUI/models/text_encoders/. You need both t5xxl_fp16.safetensors and clip_l.safetensors. On 8 GB cards, use t5xxl_fp8_e4m3fn.safetensors — halves T5 memory, ~1% fidelity loss. I cannot spot the difference in side-by-side tests at 1024². At 1536² the fp8 softens slightly.

  • VAE → ComfyUI/models/vae/ae.safetensors. FLUX's 16-channel autoencoder. Do not point this at an SDXL VAE.

  • VRAM footprints I measured on a 4090, 1024², dev:

    • FP16 (full): ~23.5 GB. Fits on 24 GB. Tight. No batching. T5 fp16 is the hog here.

    • FP8 (e4m3fn diffusion model): ~12.4 GB. Comfortable on 12 GB. My default for client work.

    • GGUF Q8: ~11.2 GB. Near-lossless. My overnight-batch default.

    • GGUF Q5_K_M: ~9 GB. Runs on 8 GB with --lowvram. Noticeable softening on fine textures.

    • GGUF Q4_K_S: ~7.1 GB. Runs on 8 GB. Soft fine detail. Good for thumbnails and previews. Not finals.

  • Custom nodes: native ComfyUI handles FLUX T2I out of the box since the August 2024 update. For GGUF loading you need ComfyUI-GGUF from city96. That is the only custom node you strictly need. For LoRA support, the native LoRA loader works but FLUX LoRAs are still a young ecosystem — quality varies wildly by trainer.

The Graph Topology

FLUX [dev] — guidance distilled (the graph I ship):

  1. Load Diffusion Model → loads flux1-dev.safetensors from diffusion_models/

  2. DualCLIPLoader → set to t5xxl_fp16 + clip_l, type flux

  3. CLIPTextEncode → single positive prompt. No negative node. Do not wire one.

  4. EmptyLatentImage → 1024×1024 (or your target res)

  5. ModelSamplingFlux → connects to the model, sets the flow-matching shift. This node is non-optional. Without it FLUX outputs noise.

  6. KSampler → CFG 1.0, euler, scheduler simple, steps 20, denoise 1.0

  7. VAEDecode → uses FLUX ae.safetensors

  8. SaveImage

With GGUF:
Same graph but replace Load Diffusion Model with UnetLoaderGGUF and point it at your .gguf file in diffusion_models/. Everything else stays identical. The quantization is transparent to the sampler — ModelSamplingFlux and KSampler do not care what precision the weights are stored in.

With a LoRA:
Insert Load LoRA between Load Diffusion Model and ModelSamplingFlux. FLUX LoRAs go in ComfyUI/models/loras/ like any other LoRA, but they must be trained for the FLUX architecture. An SDXL LoRA on a FLUX model produces silent garbage — it loads, it runs, the output looks wrong, and no error tells you why.

Optimization & Production Tips

  • Resolution scaling is not linear. FLUX tolerates 768²–1536² thanks to RoPE, but joint attention cost is quadratic in patch count. 1024² is the sweet spot. 1536² eats ~2.25× the VRAM and rarely improves composition proportionally — it gives you more pixels, not better pixels. Push to 1536² only when the brief demands print resolution, then upscale from 1024² instead if you can.

  • T5 is the silent VRAM killer. If you OOM during the encode step (not the sample), you hit the T5 wall. Symptoms: the render crashes before the progress bar moves, or it crashes at 0%. Switch T5 to fp8. Same fix as the 8 GB card path. The fidelity hit is invisible at 1024² and barely visible at 1536².

  • Step count is not where you save time. On dev, 12 steps gives you 90% of the quality. 20 steps gives you 98%. 28 steps gives you 99.5% and costs 40% more time. I ship at 18–22 steps for client work. Schnell at 4–8 steps for previews.

  • Seed stability is a FLUX strength. Flow matching is a smoother trajectory than epsilon prediction, so FLUX holds composition across step-count changes better than SDXL. I have changed from 20 to 28 steps on the same seed and composition held. On SDXL the same change can flip the entire composition. Use this for A/B testing — lock the seed, vary one parameter at a time.

  • Batching FLUX is expensive. Joint attention × batch × quadratic patches. Batch=2 at 1024² on FP8 ate ~18 GB in my tests. If you need throughput, batch on GGUF Q4 only, and keep batch=2 max on 12 GB. On 24 GB you can push batch=3 at FP8. Past that, render sequentially — it is faster than fighting the OOM-retry loop.

  • --lowvram works but hurts. On 8 GB cards, --lowvram pages the model to system RAM between steps. It runs. It is 2–3× slower. Fine for overnight batches, agonizing for iteration. If you are on 8 GB, use GGUF Q4 and --lowvram together — Q4 shrinks the model enough that paging is less frequent.

  • Do not wire a negative prompt on distilled FLUX. It is ignored. It wastes graph space. It confuses collaborators who assume it is doing something. On non-distilled FLUX, the negative is load-bearing — keep it short, under 30 tokens, focused on what to suppress (blurry, deformed, watermark).

Where FLUX Fits in a Real Pipeline

FLUX is the hero-shot engine. That is its role. Prompt-heavy concept art, multi-subject editorial, anything where the brief is "make the image match the description" — FLUX is the cleanest answer today. Its weakness is control. ControlNet support exists but is immature. IP-Adapter coverage is thin. LoRA quality varies by trainer. For pose-locked work, identity-locked work, or rapid style iteration, SDXL with ControlNet is still the stronger stack. When a brief needs both fidelity and structural control, the pragmatic move is FLUX for the hero render, then SDXL + ControlNet for refinement passes. Upscaling is backbone-agnostic — 4x-UltraSharp or ECM applied post-VAE works fine on FLUX output. I have shipped this two-backbone stack on three jobs this quarter. It is more graph complexity, but it is the honest way to get both.

Downloadable Workflow & References



Post a Comment

0 Comments