What You'll Build
A local Qwen-Image-2.1 setup on a 12 GB RTX 3060 in ComfyUI, using the same int8 weights ComfyUI's own templates load: text-to-image at 1024×1024 and at the model's native 2048×2048, RGBA output with a real alpha channel, and instruction-based editing with reference images. Qwen-Image-2.1 is a 7B single-stream diffusion transformer (32 layers, per the repo's transformer/config.json) behind a Qwen3-VL-8B text encoder and a 64-channel RGBA VAE, released 2026-09-20. On this card the transformer is not the hard part — 6.758 GiB in int8. The text encoder is: at 8.709 GiB it is the larger file, and its stage is the one that comes closest to 12 GiB.
⚠️ Read the licence before you download 17 GB. The weights ship under the Qwen Research License Agreement. Section 1.i defines "Non-Commercial" as the only permitted use — it "shall mean for research or evaluation purposes only." — and section 2.a grants the licence "FOR NON-COMMERCIAL PURPOSES ONLY". The grant is worldwide and there is no clause excluding any territory (section 4.a only reminds you that export controls may apply); the restriction is on purpose, not on place. Section 4.b reaches outputs in one specific case: "If you use the Materials or any outputs or results therefrom to create, train, fine-tune, or improve an AI model that is distributed or made available, you shall prominently display “Built with Qwen” or “Improved using Qwen” in the related product documentation." Every repack on this page — Comfy-Org's int8 files included — is a derivative and carries the same terms. Section 2.b gives an address for a commercial licence; a reader reports in the vendor's discussion #7 that mail to it bounces. This is a reader's summary of the text, not legal advice.
Hardware data: RTX 3060 (12 GB VRAM) · int8 DiT 6.758 GiB + int8 text encoder 8.709 GiB — 15.467 GiB together, so never both fully resident · See benchmark data
ℹ️ Nothing on this page was measured on an RTX 3060. No run of this model on a 12 GB card, or on any Ampere card, turned up on the surfaces searched for this page on 2026-09-21: every comment in the Hacker News launch thread, every comment in every discussion on the vendor's Hugging Face repo and on the Comfy-Org repack, the vendor's GitHub issues, and the 100 newest issues and pull requests on the ComfyUI tracker. Outside those surfaces, the discussions on one community GGUF repository,
abenzerps/Qwen-Image-2.1-Uncensored-GGUF(read 2026-09-23), hold an RTX 3090 Ti report from 2026-09-21 that its Q4_K_M file worked, with no timing (#4); the repository was re-released on 2026-09-22 with renamed files, so today's Q4_K_M may not be the file that ran. They also hold two RTX 3060 attempts that failed: one on anormalized_shapeerror at run time, which the repository owner traces to an old ComfyUI-GGUF commit (#4), and one on the GGUF loader'sUnknown model architectureerror (#2). None of them is this page's int8 template path. Also outside those surfaces, the validation record of alesha-pro's install package (dated 2026-09-21, read 2026-09-23) runs the template's three files, through the author's own workflows at 40 and 50 steps, on one RTX 3090 24 GB: an Ampere card with twice this one's memory, on Linux. The package's launcher passes--disable-dynamic-vram --reserve-vram 1(install/setup.pyL128), i.e. the legacy loader, and the record itself does not print its launch line. Reddit could not be read from the session that wrote this page. Every VRAM figure below is derived from byte counts and from ComfyUI's own source at tagv0.37.0, and the arithmetic is shown so you can check it. If you run it, post your numbers.
Requirements
| Component | Minimum | This recipe |
|---|---|---|
| GPU | 12 GB VRAM, NVIDIA | RTX 3060 (12 GB) — not measured; the budget below is derived (/contribute) |
| RAM | 32 GB recommended | — the three files are 16.096 GiB, and what is not on the card lives in RAM |
| Storage | 17,283,091,112 B = 16.096 GiB (int8 DiT + int8 encoder + VAE) | — byte counts from the Comfy-Org tree API |
| Software | ComfyUI ≥ v0.37.0, PyTorch cu130, driver ≥ 580 | — |
The RTX 3060 is Ampere, compute capability 8.6 in NVIDIA's own table. The whole page turns on that number: Ampere has INT8 tensor cores and no FP8 or FP4 ones, and ComfyUI decides per device which weight formats run natively from exactly that.
The three files the official templates load, byte-exact from the Comfy-Org repack's tree API (commit ace0edeb37, read 2026-09-21 — this is launch week, re-check the sizes before you rely on them):
| File | Bytes | GiB | Destination |
|---|---|---|---|
diffusion_models/qwen_image_2.1_int8_convrot.safetensors | 7,256,783,064 | 6.758 | models/diffusion_models/ |
text_encoders/qwen3vl_8b_int8_convrot.safetensors | 9,350,798,360 | 8.709 | models/text_encoders/ |
vae/qwen_image_2.1_vae_bf16.safetensors | 675,509,688 | 0.629 | models/vae/ |
The "Staged" figures in the RX 9070 XT log quoted in issue #16437 — int8 DiT 6920 MB, int8 encoder 8916 MB, VAE 644 MB — are these same file sizes in MiB. They show that staging does not inflate the weights; they are not peak VRAM readings.
The same repo holds a bf16 DiT (14,230,280,616 B = 13.253 GiB — past this card on its own), a bf16 encoder (17,534,334,616 B = 16.330 GiB), a w4a8 encoder (6,312,105,364 B = 5.879 GiB — the one alternative that matters here), and two qwen3.5_9b_…_pe_… files, which are prompt enhancers, not encoders. The repo's recursive tree lists ten files, and its two DiT builds are bf16 and int8; there is no fp8 or nvfp4 DiT in it, nor any Qwen-Image-2.1 file in the other five Comfy-Org/Qwen-Image* repos. The ComfyUI docs page for this model, synced with the templates on 2026-09-22 (Comfy-Org/docs 9d133794), now lists the int8 encoder as the one the templates load and the bf16 one as the full-precision alternative that needs more memory; until then it listed only the bf16 one. On this card the bf16 encoder cannot be resident at all, so follow the templates.
What actually gates this card
ComfyUI has two loaders, and they budget VRAM differently. On this card the default is DynamicVRAM: main.py at v0.37.0 enables it on any NVIDIA device once PyTorch is 2.8 or newer and comfy-aimdo initialises. You land on the legacy estimate-based loader instead if you pass --disable-dynamic-vram (or --highvram, --gpu-only, --novram, --cpu), or if the startup log says Falling back to legacy ModelPatcher — PyTorch older than 2.8, or no working comfy-aimdo. Both views below come from ComfyUI's source at tag v0.37.0 (comfy/model_management.py, comfy/model_base.py, comfy/sd.py, comfy/model_patcher.py), from comfy-aimdo v0.5.5 (the version requirements.txt pins), and from the byte counts above.
Two estimates appear in both views. Both are ComfyUI's planning figures, not peaks anyone read off nvidia-smi, and only the legacy loader acts on them:
- The sampler's activations.
area × dtype_size × 0.01 × memory_usage_factorMiB, withmemory_usage_factor = 6.0for this model incomfy/supported_models.pyandareathe latent grid: 64×64 = 4,096 tokens at 1024², 128×128 = 16,384 at 2048², because the VAE downsamples 16× and the transformer uses patch size 1. In bf16 that is 0.480 GiB and 1.920 GiB for one image. ComfyUI computes it twice (comfy/sampler_helpers.py): at twice the batch even at cfg 1, 0.960 and 3.840 GiB, which sets how much the legacy loader frees before loading; and at one image, 0.480 and 1.920 GiB, the minimum that decides whether it loads the model whole. The tables below use the minimum. The source carries a TODO saying the formula needs tweaking. - The VAE decode. For this VAE
comfy/sd.pyestimates900 × h × w × 256 × dtype_sizebytes over the latent grid: 1.758 GiB at 1024², 7.031 GiB at 2048².
DynamicVRAM (the default). ComfyUI's own reserve plays no part here. load_models_gpu() still computes it and passes it down, but ModelPatcherDynamic.partially_load() accepts that extra_memory argument and never uses it. The floor is comfy-aimdo's, and it differs by OS. On Linux, src/plat.h defines VRAM_HEADROOM (256 * 1024 * 1024) — 0.25 GiB — and keeps that much free against the card's live free VRAM, i.e. after whatever the desktop and the CUDA context already hold. The Windows build uses src-win/shmem-detect.c instead, which keeps 512 MiB — 0.5 GiB — free against both the WDDM budget and NVML's free-VRAM reading (96 MiB if it has to fall back to cuMemGetInfo). Its budget takes the larger of that live check and a second one against the card's total capacity, then adds any extra headroom. --reserve-vram N feeds only the second, total-capacity check — comfy-aimdo's own control.py says raising it above 256 MB is honoured but lowering it below changes nothing — and --vram-headroom N adds N GiB on top of both. Weights are loaded on demand and evicted when an allocation needs the room — the comfy-aimdo README describes "on-demand offloading of model weights when the primary pytorch VRAM allocator comes under pressure". So a stage never fails for want of room for its weights; what the numbers below tell you is whether its weights can stay resident for the whole stage, or have to be evicted and re-read part-way.
| Stage (DynamicVRAM) | Weights | + ComfyUI's estimate | + headroom | Stage total | Against 11.622 GiB (Linux) |
|---|---|---|---|---|---|
| Text encode, int8 encoder | 8.709 GiB | — (none made) | 0.25 GiB | 8.959 GiB | 2.663 GiB spare |
Text encode, w4a8 encoder | 5.879 GiB | — | 0.25 GiB | 6.129 GiB | 5.493 GiB spare |
| Denoise at 1024² | 6.758 GiB | 0.480 GiB (minimum) | 0.25 GiB | 7.488 GiB | 4.133 GiB spare |
| Denoise at 2048² | 6.758 GiB | 1.920 GiB (minimum) | 0.25 GiB | 8.928 GiB | 2.693 GiB spare |
| VAE decode at 1024² | 0.629 GiB | 1.758 GiB | 0.25 GiB | 2.637 GiB | 8.985 GiB spare |
| VAE decode at 2048² | 0.629 GiB | 7.031 GiB | 0.25 GiB | 7.910 GiB | 3.712 GiB spare — if the decode needs all of it, the DiT's 6.758 GiB does not fit beside it |
The table is for Linux: the 0.25 GiB headroom, against the 11,901 MiB (11.622 GiB) an RTX 3060 reported to ComfyUI on Linux in #12774, the lowest of the Linux readings found on the ComfyUI tracker, which run up to 12,036 MiB in #8305; that one would add 0.132 GiB to every spare figure. On Windows the card reports 12,288 MiB, a full 12 GiB (#16073), and the headroom is 0.5 GiB, so every stage total is 0.25 GiB higher and every spare figure 0.128 GiB higher than in the table: the encoder stage becomes 9.209 GiB, with 2.791 GiB spare.
DynamicVRAM acts on neither estimate. It ignores the sampler's, and because the VAE is itself a dynamic model and free_memory() does not unload one dynamic model for another, the decode estimate only sets how many images are decoded per batch (comfy/sd.py). In this table both stand in for working memory the loader does not set aside: DiT weights leave the card only when real allocations need the room.
Legacy loader (only if you are on it). Here the reserve is real: minimum_inference_memory() is 0.8 GiB plus EXTRA_RESERVED_VRAM, which is 400 MiB (0.391 GiB) on Linux — 1.191 GiB. On Windows it is 600 MiB, and a further 100 MiB is added only when the card exceeds 15 GiB, so a 12 GB card on Windows gets 1.386 GiB. The loader keeps the larger of that reserve and the stage's minimum estimate plus EXTRA_RESERVED_VRAM free, and loads the model whole only if what remains holds it — otherwise it loads it partially. The totals are its residency thresholds:
| Stage (legacy loader, Linux) | Weights | What the loader keeps free | Stage total | Against 11.622 GiB (Linux) |
|---|---|---|---|---|
| Text encode, int8 encoder | 8.709 GiB | 1.191 GiB (the reserve) | 9.899 GiB | 1.723 GiB spare |
Text encode, w4a8 encoder | 5.879 GiB | 1.191 GiB | 7.069 GiB | 4.553 GiB spare |
| Denoise at 1024² | 6.758 GiB | 1.191 GiB (the minimum's 0.480 + 0.391 is below the reserve) | 7.949 GiB | 3.673 GiB spare |
| Denoise at 2048² | 6.758 GiB | 2.311 GiB (minimum 1.920 + 0.391) | 9.069 GiB | 2.553 GiB spare |
| VAE decode at 1024² | 0.629 GiB | 2.149 GiB (1.758 + 0.391) | 2.778 GiB | 8.844 GiB spare |
| VAE decode at 2048² | 0.629 GiB | 7.422 GiB (7.031 + 0.391) | 8.051 GiB | 3.571 GiB spare — only with the DiT partly unloaded (below) |
On Windows, against the 12 GiB the card reports there, the larger reserve leaves the encoder stage 1.905 GiB spare.
The "spare" column in both tables is against the whole capacity the card reports (11.622 GiB on Linux, 12 GiB on Windows). The desktop's share and the CUDA context come out of it under either loader: both read live free VRAM when they decide what stays resident, which is why neither needs a flag for them, but neither leaves them outside that capacity either. 2.663 GiB (DynamicVRAM on Linux; 2.791 GiB on Windows) or 1.723 GiB (legacy on Linux; 1.905 GiB on Windows) holds a desktop and a CUDA context comfortably; the thin margins further down do not.
Four things follow, in either view.
The encoder and the DiT never sit on the card whole at the same time. 6.758 + 8.709 = 15.467 GiB, and even with the w4a8 encoder it is 12.637 GiB — past 12 GiB before any headroom. Under DynamicVRAM ComfyUI does not unload one model to make room for the other — the comment in free_memory() says "don't actually unload dynamic models for the sake of other dynamic models" — and comfy-aimdo evicts weights as allocations need the room. The practical consequence is an inference from the arithmetic, not a measurement: a new prompt re-runs the encoder, so its weights have to come back onto the card, and the DiT's have to come back when sampling starts. One tier up, on a 16 GB RX 9070 XT, the reporter of #16437 describes the same pressure: "The 7B DiT (6920 MB staged) plus the qwen3vl_8b text encoder (8916 MB staged) cannot co-reside in 16304 MB." The same report notes that a run with only the seed changed reuses the cached conditioning and reloads nothing — and it is a report of output corruption after exactly this reload, on AMD; see Troubleshooting.
The encoder stage is the binding one in both views: 8.959 GiB under DynamicVRAM (9.209 GiB on Windows), 9.899 GiB under the legacy loader (10.095 GiB on Windows), against 11.622 GiB on Linux and 12 GiB on Windows. Neither loader budgets for the encoder's own activations, so an edit with several large reference images — which all pass through the encoder's vision tower — has an unestimated working set on top.
Why 12 GB is the floor for this page. 12 GB is the smallest card size in this catalogue on which every stage keeps its weights whole under both loaders; that is the definition this page's min_vram_gb uses. On 8 GB the template's int8 encoder cannot stay on the card — 8.709 GiB of weights plus 0.25 GiB of headroom on Linux (0.5 GiB on Windows) already exceeds it — so DynamicVRAM would evict and re-read it part-way through every encode, which nobody has measured. The RTX 5060 page in this series documents the install aimed at 8 GB (the w4a8 encoder).
At 2K the decode is what is tight. The 2048² decode estimate is 7.031 GiB. The legacy loader reserves it: before the decode it frees 1.1 × the VAE plus the 7.422 GiB reserve, 8.114 GiB on Linux (load_models_gpu() in comfy/model_management.py), so the DiT's 6.758 GiB cannot stay beside it (14.872 GiB) and is partly unloaded until that much is free. DynamicVRAM reserves nothing for it; if the real decode needs that much, the DiT cannot stay either (14.669 GiB on Linux), and the room comes from evicting DiT weights, which then have to be re-read for the next image. ComfyUI also keeps a fallback for a decode that runs out anyway: it logs "Warning: Ran out of memory when regular VAE decoding, retrying with tiled VAE decoding." and tiles it. So 2K should complete; whether it completes in one pass on this card is precisely what nobody has measured.
Installation
1. ComfyUI v0.37.0 or newer, on a cu130 PyTorch
Support landed in ComfyUI core with PR #16400 (author kijai, merged 2026-09-19), and tag v0.37.0 contains it — the compare view shows the tag eight commits ahead of that merge and none behind. The v0.37.0 release itself was published at 07:35 UTC on 2026-09-21 — a day after the tag, so for the first day the only way in was git — and it carries Windows portable builds.
Windows portable. Take ComfyUI_windows_portable_nvidia.7z from that release. The ComfyUI README says "The portable above currently comes with python 3.13 and pytorch cuda 13.0." — which is the build this card needs. Do not take ComfyUI_windows_portable_nvidia_cu126.7z: the README labels it for GTX 10-series and older cards, adding "DO NOT USE THIS ON NEWER 20 SERIES AND ABOVE GPUS", and on this card a CUDA 12 build switches off the fast int8 kernels (step 2).
Git (Linux; on Windows use the portable, or swap the activation line as noted in the block). Install PyTorch from the cu130 index first, then the requirements — the torch line in requirements.txt is unpinned, so the order decides which build you get:
git clone https://github.com/Comfy-Org/ComfyUI
cd ComfyUI
python -m venv venv
source venv/bin/activate # Windows cmd/PowerShell: venv\Scripts\activate
pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu130
pip install -r requirements.txt
python -c "import torch; print(torch.__version__, torch.version.cuda)"
git describe --tags
The print must show a +cu130 torch with 13.0 beside it (the cu130 index carries builds from torch 2.9.0 to 2.14.0), and git describe must read v0.37.0 or something later such as v0.37.0-5-g…. The README states the requirement as policy — "Using a cu130 or above version of pytorch is required on Nvidia 20 series and above." — and a CUDA 13 build needs an NVIDIA driver from the 580 branch or newer, the minimum NVIDIA's CUDA release notes give for CUDA 13.x. requirements.txt at the tag pins comfy-kitchen==0.2.35 and comfyui-workflow-templates==0.11.66; the latter is the templates release that switched the Qwen-Image-2.1 templates to the int8 encoder.
Tag or master? Two follow-up PRs aimed at 2.1 merged after the tag and are on master, not in v0.37.0 or its portable: PR #16429, which changes where the edit path's K/V cache is placed — it matters on a card this full, see Editing below — and PR #16430, which adds ComfyUI's memory compiler to the 2.1 transformer blocks, aimed by its author at runs where offloading is the bottleneck. A third post-tag change to the same model file, PR #16419 (commit c194dd00cd), lets model files say which attention each block uses. A git install tracking master has all three; if you only generate from text, the tag is enough. One caveat if you take master to edit images: open issue #16443 reports a hard abort, Fatal Python error: Aborted at 0/25, on image editing / img-to-img with an input image. It comes from two RTX 5060 Ti 16 GB owners whose machines also hold a second card: the reporter's second RTX 5060 Ti, on Windows, and a second user's extra RTX 3060 12 GB (that user does not say which card ran it). The second card does not look like the cause: on 2026-09-22 the reporter wrote "I also tested launching ComfyUI with --cuda-device 0 to force a single GPU, but the same crash still occurs." Neither has seen it on text-to-image. Both describe it as intermittent and point at image size: the second user saw it only once img-to-img went above 1 MP, and the reporter's failing workflow uses two input images of about 1500×1000, with no crash so far after swapping in smaller ones; both say they have run too few images to be sure (thread read 2026-09-23: four comments, no maintainer reply). Open PR #16450 blames the allocation-recording wrapper that #16430 put around the block loop, code that exists only on master; the cause is unconfirmed and the proposed fix had no maintainer review when read on 2026-09-23. The v0.37.0 tag does not have that wrapper. A different abort, reported on a master build in PR #16481, is under Troubleshooting.
2. What Ampere gets from the int8 files, and what it does not
Read this before choosing an encoder, because the file names invite the wrong choice. Both int8 files carry, per layer, the quantisation format int8_tensorwise with convrot: true and a group size of 256 (read from each file's safetensors header). What happens to those weights differs between the two models.
For the diffusion model, ComfyUI decides per device which formats run natively in get_disabled_quant_formats() in comfy/ops.py, and prints the result when it loads it, as a line starting Native ops: followed by emulated ops:. For a compute-capability 8.6 device the checks in model_management.py resolve like this: supports_fp8_compute() is False (major 8, minor below 9), supports_nvfp4_compute() and supports_mxfp8_compute() are False (major below 10), and supports_int8_compute() is True — it has no compute-capability test at all and excludes only MPS, Intel XPU, DirectML and ixuca. So on this card the log lists int8_tensorwise, convrot_w4a4 and asym_w4a8_int8 as native, and nvfp4, mxfp8 and the two float8 formats as emulated. An emulated layer's weight is dequantised to bf16 for the matmul.
For the text encoder that table does not apply. At v0.37.0 every quantised encoder is built with mixed_precision_ops(..., full_precision_mm=True) in comfy/sd1_clip.py (the log says Using MixedPrecisionOps for text encoder), so each weight is dequantised for its matmul on every card. The one call that switches quantised matmuls back on, use_quantized_matmul, wraps only generate() — LLM text generation, not the conditioning encode this model uses. The encoder's file format is therefore a memory choice, not a speed choice. Three consequences:
- The int8 DiT is the right file here, not a compromise. Its matmuls run as INT8 GEMMs. With a cu130 PyTorch, the
comfy-kitchenCUDA backend rotates and quantises the activations in one fused kernel and runs the GEMM through its CUTLASS INT8 path, which its source (backends/cuda/__init__.py, pinned at the commit taggedv0.2.35) enables for compute-capability major 8 and above. - Without cu130 this page's templates still run, the slow way. The gate is in
comfy/quant_ops.py: below CUDA 13 it callsck.registry.disable("cuda")and logs "WARNING: You need pytorch with cu130 or higher to use optimized CUDA operations." comfy-kitchen then falls through its backend order (cuda,triton,eager; ComfyUI disablestritonby default) toeager, whoseint8_linearapplies the Hadamard rotation as ordinary torch ops, quantises the activations per row, and still runs an integer GEMM throughtorch._int_mmbefore rescaling in chunks. That is a working INT8 path with the fusion gone — not a dequantisation to bf16, and not a failure. It is also why theNative opsline will not warn you: it reflects the hardware, not which comfy-kitchen backend is alive. The tells are the WARNING above, and the startup lineFound comfy_kitchen backend cuda:showing'disabled': True. That holds for the two templates here, neither of which has aTextGeneratenode. The optional prompt-enhancer stage is another matter: on an sm_86 12 GB card with v0.37.0, a cu128 PyTorch and driver 575, #16449 reportsTextGeneratewith a Qwen3-VL encoder failing withCUDA driver version is insufficient for CUDA runtime version, and a ComfyUI maintainer replied that CUDA 12 on newer GPUs is not supported. - For the encoder, pick by size. Comfy-Org's encoder repo
Comfy-Org/Qwen3-VLalso holdsqwen3vl_8b_fp8_scaled.safetensors(10,588,637,512 B = 9.861 GiB) andqwen3vl_8b_nvfp4.safetensors(6,305,221,764 B = 5.872 GiB). Both carry the DeepStack key and the 4096-wide merger thatcomfy/sd.pyuses to identify Qwen3-VL-8B, so undertype: qwen_imagethey would be routed to the 2.1 encoder class and should load; nobody in the three repos' discussion tabs reports running either with 2.1, and this page did not either. Since every encoder format is dequantised for the encode anyway, only size matters: the fp8 file is larger than the int8 one, and the nvfp4 file is within 7 MB of thew4a8encoder that ships in the repack beside the int8 one. If the encoder stage is what you need to shrink, takew4a8— it saves memory, not time.
Why the encoder identity is worth a paragraph: Comfy-Org's qwen3vl_8b_bf16.safetensors in the 2.1 repo carries the same LFS sha256 (68bdc82b…) as the file of that name in Comfy-Org/Qwen3-VL, uploaded there on 2026-06-06 to a repo whose card lists Qwen/Qwen3-VL-8B-Instruct as a base model — three months before the 2.1 weights were public. The vendor's own text_encoder/ shards sum to 17,534,339,488 B and the stock Qwen3-VL-8B-Instruct shards to 17,534,339,512 B, differently split. Two readers who compared the tensors reached the same answer on the vendor's discussion #5: "我比较过 tensor 数值 原版 instruct 没有增量训练" (FIT17, community: compared the tensor values — the original Instruct, no incremental training), and a second reply reports a tensor-by-tensor comparison with identical hashes. The encoder is the stock model, which is why encoder quants from the older repo are interchangeable in principle.
3. Download the weights
The repo's folder names match ComfyUI's models/ layout, so --local-dir models lands each file where the loaders look. On a git install, run this from inside the ComfyUI folder with the venv active — the shell step 1 left you in:
pip install -U huggingface_hub
hf download Comfy-Org/Qwen-Image-2.1 diffusion_models/qwen_image_2.1_int8_convrot.safetensors --local-dir models
hf download Comfy-Org/Qwen-Image-2.1 text_encoders/qwen3vl_8b_int8_convrot.safetensors --local-dir models
hf download Comfy-Org/Qwen-Image-2.1 vae/qwen_image_2.1_vae_bf16.safetensors --local-dir models
On the Windows portable there is no pip or hf on PATH. Use the Python the portable ships, python_embeded\python.exe — the same interpreter its run_nvidia_gpu.bat starts ComfyUI with and its updater runs pip through — from the portable's top folder, the one holding python_embeded and ComfyUI:
python_embeded\python.exe -s -m pip install -U huggingface_hub
python_embeded\python.exe -s -m huggingface_hub.cli.hf download Comfy-Org/Qwen-Image-2.1 diffusion_models/qwen_image_2.1_int8_convrot.safetensors --local-dir ComfyUI\models
python_embeded\python.exe -s -m huggingface_hub.cli.hf download Comfy-Org/Qwen-Image-2.1 text_encoders/qwen3vl_8b_int8_convrot.safetensors --local-dir ComfyUI\models
python_embeded\python.exe -s -m huggingface_hub.cli.hf download Comfy-Org/Qwen-Image-2.1 vae/qwen_image_2.1_vae_bf16.safetensors --local-dir ComfyUI\models
(-m huggingface_hub.cli.hf is the module behind the hf command; it runs directly because cli/hf.py ends in a __main__ guard.)
Check the sizes against the table above. If you settle on the smaller encoder, the fourth file is text_encoders/qwen3vl_8b_w4a8.safetensors from the same repo — select it in the template's CLIP loader. Do not confuse it with the two qwen3.5_9b_qwen_image_2.1_pe_*.int8_convrot.safetensors files beside it: those are Qwen3.5-9B prompt-rewriting models for an optional LLM stage, and a reader on the repack's discussion #4 who swapped one in as the text encoder got garbled images. As another reader put it in the same thread, "The PE models only for PE." (Landsharkbaby, community). At 9,471,072,252 B each they are another encoder-sized load on a card that already cannot hold one beside the DiT; skip them here.
Running
Start ComfyUI normally — no --lowvram, no --reserve-vram, nothing:
python main.py
On this card with a cu130 PyTorch, DynamicVRAM is on by default at v0.37.0: main.py enables it on NVIDIA when PyTorch is 2.8 or newer and comfy-aimdo initialises, and the log then reads DynamicVRAM support detected and enabled. Under it the text encoder runs on the GPU, weights that do not fit are paged rather than refused, and --lowvram is documented in comfy/cli_args.py as "Doesn't do anything if dynamic vram is enabled." — so adding it out of 12 GB habit changes nothing. You do not need a flag for the desktop: comfy-aimdo's live check keeps 0.25 GiB free on Linux (0.5 GiB on Windows) after whatever the desktop already holds (the desktop still comes out of the capacity the card reports, see Requirements). If you want more kept free anyway, use --vram-headroom N, which adds N GiB on top of both of comfy-aimdo's checks. --reserve-vram N is weaker under DynamicVRAM — it only raises the check against the card's total capacity — and it is also what comfy/model_management.py uses as the legacy loader's reserve.
Text-to-image
Open the Template Library and load Qwen Image 2.1: Text to Image (image_qwen_image_2_1_t2i.json, read here at workflow-templates v0.11.66, the version v0.37.0 pins). The values that govern it sit on the outer subgraph node: UNETLoader → qwen_image_2.1_int8_convrot.safetensors, CLIPLoader → qwen3vl_8b_int8_convrot.safetensors with type qwen_image, VAELoader → qwen_image_2.1_vae_bf16.safetensors, 25 steps, cfg 1, euler / simple, 1024×1024. The template's own note explains the setting people change first: "negative_prompt: unused while cfg is 1." At cfg 1 ComfyUI skips the negative pass entirely; raising cfg adds a second model pass on every step. For native 2K the note says to set the Resolution Selector to 1:1 at 4 megapixels. The vendor's diffusers example runs 40 steps; the template's 25 is ComfyUI's choice, not Qwen's. One user on Comfy-Org's discussion #11, Xenodermus, reports faint banding on skin, fabric and fur at the template's 25 steps, with the int8 and bf16 diffusion models and encoders alike and with the simple and normal schedulers, and at 1024×1024 writes "Artifact disappeared completely at 40"; later the same day, after switching to another user's workflow and toning down the prompt, they report no streaks. It is one user's report, with no Comfy-Org reply as of 2026-09-23.
For a transparent image, wrap the prompt the way the model card does — This is an RGBA image with transparency. <your subject>. The image has alpha channel and the background is transparent. — and keep the template's SaveImageAdvanced at PNG, 8-bit, sRGB, which keeps the alpha channel.
Expect the first run to encode the prompt, sample, then decode; expect a prompt change to repeat the encode and move weights back and forth; expect a seed-only change to skip the encode.
Editing with reference images
Load Qwen Image 2.1: Image Edit (image_qwen_image_2_1_image_edit.json, same release). Same three loaders, plus a TextEncodeQwenImage21 node with the VAE connected and ten reference inputs exposed (the node has sixteen; the model card says up to ten), and a QwenImage21Cache node at auto / default. Reference images are seen by the encoder's vision tower and, because the VAE is connected, spliced into the sequence as latents. The text and reference tokens are the same on every step, so their attention K/V are computed once and cached — PR #16400 puts the gain at about 1.7× on edits. The cache node's tooltip in comfy_extras/nodes_qwen.py on where that cache goes: "auto uses spare VRAM, then RAM. cpu (RAM) is prefetched behind compute and costs little speed."
On a 12 GB card, where the cache lands decides the speed. The cache costs 2 × 32 layers × 4096 × 2 bytes = 0.5 MiB per cached token, so one 1024×1024 reference (4,096 latent tokens) is 2 GiB before the text. At v0.37.0 comfy/ldm/qwen_image21/model.py places it in auto mode only if four times that size is free — on the GPU first, then in system RAM — and otherwise recomputes the whole prefix on every step. With the DiT already filling the card, that means about 8 GiB of free RAM per 1024² reference, and on a 16–32 GB machine that may not be there. PR #16429, on master only, exists because this check was too strict; its author lists two problems: "It requires the VRAM to be free at the time of the check to use VRAM mode which gets disrupted by smart memory + dyn vram" and "It requires 4x RAM to be free and doesnt account the pin quotas at all". On the PR's own test machine — an RTX 5080 with 32 GB RAM, a newer and faster card than this one — an edit with two references went from the full-recompute fallback at 4.01 s/it to 1.02 it/s. If you run the tag and edits are slow, set the cache node's device to cpu: that skips the four-times check (the source still wants twice the cache size free in RAM), or move to master, where open issue #16443 reports a hard abort on image edits (see Tag or master?). A cache kept in RAM is pinned host memory by default on NVIDIA (at the tag pin_memory() refuses any tensor not on the CPU, comfy/model_management.py line 1648), and ComfyUI unpins it at the sampler's cleanup (_free_slot() and free() in comfy/ldm/wan/model_animate2.py), which is where PR #16481 reports its abort on post-tag master, blaming the unpin although its stack's innermost frame is free() at line 169, with no report at the tag found (Troubleshooting); a cache on the GPU pins nothing.
The template sets the encode node's resolution to 0, and its note says why: "This template starts at 0: no resize beyond a multiple of 32." That default interacts with an open defect in which certain reference sizes render the edit as noise, and the two reports so far disagree on which sizes — read the Troubleshooting entry before you rely on resolution=0.
Smaller DiT builds: what they change on 12 GB
The binding stage on this card is the text encoder, so a smaller transformer does not move the ceiling; the encoder is the lever (w4a8, above). What a smaller DiT would change is 2K: a transformer that stays resident beside the 2048² decode is not evicted and re-read for every image. Taking ComfyUI's decode estimate as the decode's size, the room left beside it on Linux is 3.712 GiB under DynamicVRAM (11.622 − 7.910) and 3.508 GiB under the legacy loader, which frees 8.114 GiB for the decode (11.622 − 8.114), before the desktop's share and the CUDA context; on Windows, against 12 GiB, it is 3.840 and 3.691 GiB. On Linux no Q4 build fits there under either loader: Abiray's Q4_K_M (3.902 GiB) and Q4_K_S (4,059,320,480 B = 3.781 GiB), leejet's Q4_K (4,197,494,816 B = 3.909 GiB) and the mixed NidAll/Qwen-Image-2.1-Mixed-Balanced build (4,203,397,480 B = 3.915 GiB) are all over the line. On Windows only Q4_K_S squeezes under it, by 0.059 GiB under DynamicVRAM, too little for the CUDA context and the desktop, so in practice they would all be evicted too. Under DynamicVRAM, the default, the Q3-and-smaller GGUFs leave a usable margin on Linux: Abiray's Q3_K_M 0.744 GiB, leejet's Q3_K (3,270,553,632 B = 3.046 GiB) 0.666 GiB, leejet's Q2_K 1.326 GiB. Under the legacy loader they leave 0.541, 0.462 and 1.122 GiB, which puts the two Q3 builds in the same thin range as the INT4 ConvRot build: it leaves 0.297 GiB under DynamicVRAM on Linux and 0.425 GiB on Windows for the CUDA context and the desktop together, thin on either system. Q5_K_M (4.664 GiB) does not fit at all. None of the builds below has a published run on a named 12 GB or Ampere card, and all appeared within a day of release.
- GGUF. Abiray/Qwen-Image-2.1-GGUF publishes Q8_0 at 7,591,579,808 B = 7.070 GiB, down through Q4_K_M at 4,189,343,904 B = 3.902 GiB (with a 2K decode, 11.812 GiB under DynamicVRAM and 12.016 GiB legacy, both over the 11.622 GiB a Linux 3060 reports) to Q3_K_M at 3,185,944,736 B = 2.967 GiB; leejet's smallest, Q2_K, is 2,561,716,256 B = 2.386 GiB. Its headers (read over an HTTP range request) declare
general.architecture = qwen_image, which city96'sloader.pyaccepts, and ComfyUI v0.37.0 then recognises the 2.1 key layout — so the stock loader should take them, as the card says. leejet/Qwen-Image-2.1-GGUF is different: its files carry no metadata keys at all (a stable-diffusion.cpp artifact), which sends the loader to its key-detection table, and only leejet's fork has a 2.1 entry in it. The two cards disagree about which loader to use, and each is right about its own files. ComfyUI-GGUF dequantises each weight to the compute dtype before the matmul, so Q8_0 saves nothing against the int8 file and gives up the INT8 GEMM. - INT4 ConvRot (W4A4). toxicdog/Qwen-Image-2.1-INT4ConvRot-ComfyUI ships a 3,666,512,184 B = 3.415 GiB DiT whose header declares the
convrot_w4a4format — native on this card by the table above — and comfy-kitchen gates its fused 4-bit kernel on compute-capability major 8, Ampere and Ada. Beside a 2K decode it comes to 11.325 GiB under DynamicVRAM (11.529 GiB legacy), and unlike the GGUFs it keeps a native matmul. Quality at 4-bit activations is the open question. - Not for this card: NVFP4. The NVFP4 DiT builds load, but
supports_nvfp4_compute()wants major ≥ 10, so on Ampere they are emulated: the memory saving survives and the kernel does not.
Results
- Speed: omitted. No timing on an RTX 3060, on any 12 GB card or on any Ampere card has been published on the surfaces this page searched (listed in the note at the top). The figures found there name an RTX 4090 (a Hacker News comment on the launch thread), an RTX 5080 (PR #16429) and an RTX 5090 (PR #16430) — all newer and faster, so none of them says anything useful about this card. Ampere timings found since, in alesha-pro's RTX 3090 record (the note at the top), come from a card with twice this one's memory, at 40 and 50 steps, with a package launcher that passes the legacy loader's flags (the record itself does not print its launch line), so its times are not repeated here as figures for this card. If you time a run — steps, resolution, seconds per image, whether the decode fell back to tiled — post it; it becomes the first datapoint on /check/qwen-image-2-1/rtx-3060.
- VRAM usage: derived, not measured. The binding stage is the text encoder. Under DynamicVRAM, the default on this card: 8.709 GiB of weights plus
comfy-aimdo's headroom — on Linux 0.25 GiB, 8.959 GiB against the 11.622 GiB the card reports there, 2.663 GiB spare; on Windows 0.5 GiB, 9.209 GiB against 12 GiB and 2.791 GiB spare — before the desktop's share and the CUDA context, which have to fit inside it (the live check counts them when it decides what to evict, so no flag is needed for them). Under the legacy loader (--disable-dynamic-vramand friends): 8.709 GiB plus ComfyUI's 1.191 GiB reserve — 9.899 GiB, 1.723 GiB spare on Linux before the same desktop and context (1.905 GiB on Windows). On Linux the denoise stage is 7.488 / 8.928 GiB at 1024² / 2048² under DynamicVRAM (7.949 / 9.069 GiB legacy), and the 2K decode, taking ComfyUI's estimate as its size, is 7.910 GiB (8.051 GiB legacy) on its own; beside it the legacy loader partly unloads the DiT until 8.114 GiB is free. No measured peak at native 2K on any consumer card was found — the one 2048² run on record, an RTX 5090 batch in PR #16430, reports step time and the staged DiT size, not a VRAM peak. - Quality notes: the VAE has a reported grid artifact. The vendor's discussion #12, titled "Diamond grid pattern caused by VAE", says "It's more noticeable when you generate a high-resolution image that has people with light skin tones and zoom in on their faces." (Rkss, community), and that a plain encode–decode round trip shows it. A reply lists mitigations — a GLSL post-process node, a node pack, or re-encoding through the Flux VAE — none of them a fix, and none tied to a resolution or a card. Asked whether the VAE or the transformer is responsible, the thread's author answered that it is the VAE and pointed back to the encode–decode test; that is a community answer, not the vendor's. Inspect native-2K portraits at 100%.
For the full benchmark data, see /check/qwen-image-2-1/rtx-3060.
Troubleshooting
TextEncodeQwenImage21 or QwenImage21Cache missing when the template loads
You are below v0.37.0. Update to the v0.37.0 portable or git pull, then check the version line at startup. The ComfyUI docs page lists not running the latest version as the first reason nodes go missing, and nodes that failed to import at startup as the second.
The startup log says you need cu130
That is the quant_ops.py gate above: your PyTorch was built against CUDA 12.x — on Windows, usually the cu126 portable. Both templates still run — the diffusion model on the eager INT8 path; a TextGenerate prompt-enhancer stage may not (step 2); reinstall PyTorch from the cu130 index (or switch to the nvidia portable) and confirm torch.version.cuda prints 13.0. A ComfyUI maintainer says the same: replying on issue #16470 to an RTX 5060 Ti user on 2.10.0+cu128 whose int8 file ran slower than a GGUF Q8_0, kijai (a repository collaborator) wrote "You need pytorch with cu130 for int8 models to work properly." A different line, Failed to import comfy_kitchen, is worse: the int8 formats these files use are defined by that package, so fix the import — pip install -r requirements.txt in the ComfyUI venv restores the pinned 0.2.35 — before you debug anything else.
Edit output is over-sharpened and speckled, or ignores the edit; text-to-image is clean
Open defect #16435, with two reports that disagree on which reference sizes trigger it. With the VAE connected to TextEncodeQwenImage21, the original reporter (Apple MPS and CPU, bf16 DiT) got broadband noise whenever the reference resolved to a 64×64 latent grid — a 1024×1024 reference at resolution=0, or resolution=1024 — while 992 and 1056 were clean. A second reporter on CUDA — an RTX 5070 Ti, v0.37.0, torch 2.13.0+cu130, the official edit graph with a bf16 DiT — found that 64×64 grid clean, but a 1536×1024 reference (grid 96×64) broken: over-sharpened, speckled, and with the edit instruction ignored, both at resolution=0 and at resolution=1248, which resolve it to the same size. On that machine resolution 512, 1024, 1056 and 2048 were clean. So the trigger is the resolved grid, not the parameter value. The two reports disagree on which grids fail. The backend is one possible explanation, but the two setups also differ in encoder precision, reference image, step count, OS, ComfyUI build and attention path, so neither report isolates a cause. The second reporter notes that both failing grids are multiples of 2048, which is an observation, not a confirmed cause. Nobody has reported on an RTX 3060 or any Ampere card. resolution 1056 and 512 were clean in both reports — use 1056 instead of the template's 0 if you see the artifact; 512 avoids it too, but shrinks the reference. Disconnecting the VAE from the node also removes it, at the cost of reference adherence (on CUDA the requested edit was no longer performed at all). A proposed fix, PR #16444, was closed without merging on 2026-09-22 by kijai; no fix is linked to #16435 now, and the issue was still open on 2026-09-23. (Its sibling report, #16433 — VAE encode broken on Apple's MPS backend — does not apply to CUDA.)
Edits are far slower than text-to-image
Most likely the K/V cache found no room and fell back to recomputing the prefix every step — see Editing above. Set QwenImage21Cache → device to cpu, try dtype int8 (the node's tooltip says it halves the cache at about bf16 accuracy), shrink the references, or move to master for PR #16429, where open issue #16443 reports a hard abort on image edits (see Tag or master?).
Shape error [1, 338, 5120] from the text encoder
The CLIP loader was given something other than the 4096-wide Qwen3-VL-8B. The reporter of the repack's discussion #2 saw exactly this error while trying the w4a8 encoder, then closed the thread as having loaded the wrong encoder. Load qwen3vl_8b_int8_convrot.safetensors or qwen3vl_8b_w4a8.safetensors — not a qwen3.5_9b_…_pe_… file.
JSONDecodeError: Expecting value: line 1 column 1 (char 0) when the text encoder loads
Check the file before anything else. On issue #16472 the template's int8 encoder failed to load with this error; kijai (a repository collaborator) replied "This is most likely a corrupt/incomplete model file.", and on 2026-09-22 the reporter confirmed that downloading it again fixed it. Compare the file's sha256 (sha256sum <file>, or certutil -hashfile <file> SHA256 on Windows) with the SHA256 its Hugging Face file page shows, and download it again if they differ.
Fatal Python error: Aborted after the second image's sampling
PR #16481, opened on 2026-09-22 by sqz269, reports this hard crash on Windows 11 with an RTX 5090, torch 2.13.0+cu130, the template's int8 diffusion model and encoder, DynamicVRAM on and QwenImage21Cache at auto: the first image completed and the second aborted during the sampler's cleanup, with text-to-image and edit workflows alike. The PR attributes it to the prefix cache's pinned system-RAM slots being unpinned while a copy may still be reading them. The report says ComfyUI 0.37.0, but its stack's line numbers (qwen_image21/model.py 238, model_base.py 2678, model_patcher.py 1318) are those of master after the tag; from v0.37.0 through v0.37.2 the same lines are 236, 2674 and 1316. The code the PR patches, PoseBranchCache._free_slot calling unpin_memory (comfy/ldm/wan/model_animate2.py), is the same at the tag, so staying on v0.37.0 is not a known fix. No report of this crash on the tag turned up on the ComfyUI tracker on 2026-09-23, which is an absence of reports, not a finding that the tag is unaffected. The PR says it is a different crash site from #16443 (see Tag or master?), and that with its change six consecutive generations completed. On 2026-09-23 it was open and unmerged, with no maintainer review.
2K runs but the log says it retried the VAE decode tiled
That is the fallback working as designed; the 7.031 GiB decode estimate at 2048² is the largest working-set estimate on this page. The decode is slower, and the image should be unchanged. A smaller DiT does not change this under either loader: DynamicVRAM already evicts DiT weights when the decode needs the room, and the legacy loader already partly unloads the DiT before the decode. A DiT small enough to stay beside the decode only saves re-reading it for the next image. What removes the tiling is more free VRAM — close what else is using the card.
Every generation reloads models
Expected when the prompt or the resolution changes, for the co-residence reason in Requirements; a seed-only change should not. If a seed-only change also reloads, something upstream of the sampler changes on every run.
Those reloads are the trigger of an open defect. Issue #16437, titled "Qwen-Image 2.1: --enable-dynamic-vram silently corrupts output after any model reload (channel slice offset, ROCm gfx1201)", reports that on an RX 9070 XT the first image after a server start is correct, and every image after the first reload — a prompt change is enough — comes back with its channels in a [B, A, B, A] pattern, subjects rendering bright green, until the server is restarted. Removing --enable-dynamic-vram fixed it for the reporter, who adds "I don't have an NVIDIA card to test whether this is ROCm-specific." No report of it on NVIDIA was found (the ComfyUI tracker's issues of the launch window were read), and the one other commenter in the thread was running a different model. If your images turn green or wrong-coloured after a prompt change, restart ComfyUI; if it keeps happening, start it with --disable-dynamic-vram, which puts you on the legacy loader and its budget in Requirements.
See also: the 2025 20B predecessor has its own page for this card, on a GGUF Q3 path that the much smaller 2.1 no longer needs — Qwen-Image on RTX 3060. Report problems and post measurements via the submission form.