self-hosted/ai
§01·recipe · video

MiniMax H3 on RTX 3080 Ti: 12 GB video+audio in ComfyUI on Ampere sm_86

videoadvanced12GB+ VRAMAug 8, 2026

This advanced recipe sets up MiniMax H3 (Hailuo 3) on the RTX 3080 Ti, needing about 12 GB of VRAM.

models
tools
prerequisites
  • You are outside the licence's Excluded Territories — the European Union, the United Kingdom, the Republic of Korea and the United States of America — and note that the restriction reaches the video you generate, not only the weights
  • NVIDIA RTX 3080 Ti (12GB VRAM), Ampere GA102, compute capability 8.6
  • 64GB system RAM is comfortable; 32GB is realistic **only** with `--disable-pinned-memory`, and then the weights stream off your SSD rather than out of cache
  • 45GB free space on an NVMe SSD — the four weight files are 42.47 GB and a 12 GB card re-reads them constantly
  • ComfyUI 0.30.0 or newer, on a CUDA 13 (cu130) build of PyTorch

What You'll Build

A locally generated clip with native stereo audio from MiniMax H3, on a 12 GB RTX 3080 Ti, riding ComfyUI's dynamic VRAM offloading. The card is Ampere GA102 at compute capability 8.6, with 12 GB of GDDR6X behind a 384-bit interface — a large GPU carrying a small amount of memory. This page is about the two things that follow from that pairing: a capacity that forces every large module off-card, and an architecture on which two of the three quantisation formats in these weight files fall back to emulation.

Be clear from the start about what kind of page this is. Nothing on it was measured on an RTX 3080 Ti, because nothing published anywhere was — see Results for how thoroughly that was checked. What it has instead is byte counts, ComfyUI's own constants, and reports from other cards each named with the hardware it came from. Where an install choice is decided by arithmetic, the arithmetic is shown; where it would need a stopwatch nobody has held, the page says so and stops.

⚠️ Read the licence before you pull 42 GB down. MiniMax H3 is not open-source. The MiniMax H3 Community License Agreement grants rights only inside an "Applicable Territory", and clause I.5 defines the Excluded Territories as "means the European Union, the United Kingdom, the Republic of Korea and the United States of America." Clause V.4 then reaches past the weights and onto the footage: "You may not use, reproduce, modify, distribute, or display the MiniMax H3 Works or any of their Outputs or results outside the Applicable Territory."

No metadata filter will warn you. The machine-readable license: facet on the model card is the uninformative other, so anything keyed on that field — HuggingFace's own filters included — sails straight past a territorial clause that exists only inside the LICENSE text. Repacking does not reset it: the Comfy-Org build installed below points back at the same agreement, and a community GGUF, int4 conversion or Turbo LoRA built on these weights is a derivative under the same terms. If you need a route through it rather than around it, MiniMax answers common questions in a licence Q&A and accepts per-deployment applications at platform.minimax.io/h3-license. None of the above is legal advice — it is what one reader took from the text, and the linked agreement is the thing with force.

Hardware data: RTX 3080 Ti (12GB VRAM) · 39.554 GiB of weights against a 12 GiB card · See benchmark data

ℹ️ The 2K in the launch coverage is not in the download. H3 reaches 2K through a separate H3-Regenerate-2K module, and the MiniMax model card says of it: "this module is not yet open-sourced. We will release it once it is ready." What runs on your card is H3-Base, which the same card documents as "H3-Base: Generates audio and video based on the H3-Context-IR output, producing results at 768p resolution." No consumer card changes that, and neither does this one.

Requirements

ComponentMinimumThis recipe
GPU12GB VRAM via ComfyUI's dynamic offloadRTX 3080 Ti (12GB), Ampere GA102, sm_86 — not measured by us, and not measured by anyone else either; see Results (/contribute)
RAM64GB comfortable; 32GB realistic with --disable-pinned-memory— see Running, this is the prerequisite most likely to waste your download
Storage39.554 GiB of weights (42.47 GB as HuggingFace reports it), NVMe strongly preferred
SoftwareComfyUI 0.30.0+, torchaudio, CUDA 13 build of PyTorch

The four files the official text-to-video template loads, byte-exact from the Comfy-Org repack's tree API, re-read for this page:

FileBytesGiBDestination
minimax_h3_fl2va_pruned_int8_convrot.safetensors20,970,379,61619.530models/diffusion_models/
qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors15,687,142,55114.610models/text_encoders/
minimax_h3_video_vae_fp16.safetensors5,207,808,4964.850models/vae/
minimax_h3_audio_vae_fp32.safetensors605,254,8080.564models/vae/

That is 39.554 GiB against 12 GiB — a shortfall of 27.554 GiB, and the transformer on its own already exceeds the card. The decimal restatement, 42.47 GB, is the figure Comfy-Org quotes for the shrunk set: Comfy-Org puts the shrink at "reduced by 66%, from 123.6 GB in full precision to 42.5 GB" with the smallest model variants selected.

Note what min_vram_gb: 12 is doing in the frontmatter. It is a filter floor — the smallest capacity on which the install below runs at all — and it comes from Comfy-Org's day-0 post: "Combining this with our dynamic VRAM offloading enables a next-generation 2K video model to run locally on a GPU like the RTX 3060." That it happens to equal this card's capacity is a coincidence of the tier, not a statement that 12 GB is what the job needs. Nothing on this page peaks at 12 GiB.

What actually gates this card

The intuition to discard first is that a 12 GB card is short of VRAM in the way that produces an out-of-memory error. It is short, by a lot, and the result is a clock rather than a crash. Here is the arithmetic, from the byte counts above and from comfy/model_management.py at tag v0.30.2.

minimum_inference_memory() is 0.8 GiB plus EXTRA_RESERVED_VRAM, and on Linux that constant is 400 MiB — a floor of 1.191 GiB. On Windows the base is 600 MiB, and a further 100 MiB is added under the comment "more extra reserved vram on 16GB+ cards". Read the indentation before you copy a Windows figure off a larger card's page: that extra term sits inside the if WINDOWS branch and behind a total_vram > 15 * 1024 test, so a 12 GB card never reaches it. The Windows floor here is 1.386 GiB, not the 1.484 GiB that applies from 16 GB up.

StageResident weightsReserve (Linux)Stage totalAgainst 12 GiB
Text encode (Qwen3-VL-32B, NVFP4-AWQ)14.610 GiB1.191 GiB15.800 GiBshort by 3.800 GiB
Denoise (the H3 DiT, pruned int8+convrot)19.530 GiB1.191 GiB20.721 GiBshort by 8.721 GiB
Decode (video VAE fp16, 124 frames at 864×480)4.850 GiB1.455 GiB6.305 GiBclears by 5.695 GiB

Only the decode row fits, and its reserve is not a guess — comfy/sd.py ships a first-party estimator for this VAE, (9.5 × frames × height × width + 270,000,000) × dtype_size × 1.03, which at 124 frames of 864×480 in fp16 gives 1.455 GiB. On Windows every row above shifts up by 0.195 GiB and none of the verdicts change.

The middle row is what this page is about. load_models_gpu decides how much of a model to leave resident with max(0, free_mem − minimum_memory_required, min(free_mem × MIN_WEIGHT_MEMORY_RATIO, …)), and MIN_WEIGHT_MEMORY_RATIO is set to 0.0 on NVIDIA — so the resident weight budget collapses to free VRAM minus the reserve: at most 10.809 GiB, and less once your desktop has taken its cut, because get_free_memory() reads torch.cuda.mem_get_info rather than the nameplate. The transformer is 19.530 GiB, so at least 8.721 GiB of it is off-card on every sampling step, and it is a dense model — the card says "H3-Omni-Transformer is a 33B-parameter dense, single-stream Transformer", so each step touches all of it.

That is the gate. Not the shader count, not the 12 GB itself. What decides whether your run finishes, and how long it takes, is system RAM, the PCIe link and the SSD — which is why every prerequisite on this page other than the licence is about the machine around the card rather than the card.

Installation

1. Put ComfyUI on a CUDA 13 PyTorch

H3's nodes ship in ComfyUI core (comfy_extras/nodes_minimax_h3.py), not as a custom node pack, and the day-0 announcement pins the floor at 0.30.0. torchaudio is imported by that module at load time — H3 denoises a soundtrack alongside the picture — so an environment assembled by hand with torch and torchvision alone dies before the queue button appears.

The CUDA gate is in ComfyUI's source, not in folklore. comfy/quant_ops.py parses torch.version.cuda, and below major version 13 it calls ck.registry.disable("cuda") and logs "WARNING: You need pytorch with cu130 or higher to use optimized CUDA operations." That single call removes the comfy-kitchen CUDA backend — the accelerated kernels for the int8_tensorwise + convrot format the transformer is stored in. Nothing raises. The run is just slower, and on a card that is already streaming most of its weights, "just slower" compounds.

There is a report suggesting the downstream consequence on a long job can be worse than slow. In discussion #36 an owner posting as jeroen3325 gets a clean 5-second clip and then, on the same workflow at 10 seconds, loses the machine: "My RTX 5090 goes beserk and the only way to stop is to restart my pc", adding "this only happens with the convrot models". A second participant, ImmenseZ, reports the symptom gone after rebuilding the install: "all sorted when I reinstalled ComfyUI but this time via Stability Matrix and selecting it to use CU130 with Pytorch". Read that at its real strength. It is a different card, and the staging line in his log — MiniMaxH3TEModel_ … 25882MB Staged — is 25.277 GiB, i.e. the int8_convrot text encoder rather than the nvfp4 file this page installs, so none of it is your configuration. The original reporter never states his own CUDA version; only the person who fixed it names one. It is not a proven causal chain. It is one more reason to treat this step as mandatory rather than as a tuning nicety.

Order matters: requirements.txt lists torch unpinned, so running it after a cu130 install resolves a default-index wheel over the top and silently undoes the gate you cleared. Install the CUDA 13 stack last, from its own index.

cd ComfyUI
git fetch --tags && git checkout v0.30.2
pip install -r requirements.txt
pip install --force-reinstall --index-url https://download.pytorch.org/whl/cu130 \
  torch torchvision torchaudio

Confirm two things in the startup log before continuing: the torch version string ends in +cu130, and comfy-kitchen's CUDA backend reports itself available. A failed import there is one buried line with no other symptom — see Troubleshooting.

2. Download the four files

pip install -U "huggingface_hub[cli]"

hf download Comfy-Org/MiniMax-H3 \
  diffusion_models/minimax_h3_fl2va_pruned_int8_convrot.safetensors \
  text_encoders/qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors \
  vae/minimax_h3_video_vae_fp16.safetensors \
  vae/minimax_h3_audio_vae_fp32.safetensors \
  --local-dir models

Run it from the ComfyUI directory you changed into in step 1. The repository's own paths are already diffusion_models/, text_encoders/ and vae/, so --local-dir models lands all four exactly where the loaders look. Two ways to get this wrong: repeating the directory you are already in, as --local-dir ComfyUI/models, buries everything in ComfyUI/ComfyUI/models/; and helpfully pointing at the leaf, as --local-dir models/diffusion_models, produces models/diffusion_models/diffusion_models/…. Both leave a node that cannot find its own weights.

Pass the filenames as positional arguments, as shown. Handing several of them to --include demotes everything after the first to a positional argument and drops the flag, with only a UserWarning to mark the moment.

Take the pruned transformer. The unpruned int8_convrot build is 31.701 GiB — 12.171 GiB more to stream on a card that is streaming everything already. Pruning here is not a precision cut: Comfy-Org's launch post describes the removed parameters as modulation weights replaced by an equivalent lookup table, with no quality loss claimed.

Then check the hash, not just the size. A MemoryError out of UNETLoader on this repack has already turned out to be a truncated download that matched on byte count — see Troubleshooting. Re-hashing a 21 GB file is cheaper than re-diagnosing one.

3. The text encoder: take nvfp4, and let the arithmetic decide it

This is the install decision with the largest memory consequence on a 12 GB card, and it is also the one place where the advice usually handed to 30-series owners points the other way. Take that counter-argument first, because as far as it goes it is correct.

The hardware objection. There is no nvfp4 hardware path before Blackwell. supports_nvfp4_compute() in comfy/model_management.py returns False for any device whose compute-capability major version is below 10, and this card is 8.6 — so on raw silicon capability an Ampere owner gets nothing from the format, which is why 30-series owners are routinely steered to the int8_convrot encoder instead. What that advice leaves out is the other side of the ledger: what the alternative costs in memory on a card this size.

The arithmetic settles it, and it is not close. Against a 12 GiB card the two encoders stage like this:

Text encoderOn diskStage total (weights + 1.191 GiB reserve)Against 12 GiB
qwen3vl_32b_minimax_h3_nvfp4_awq14.610 GiB15.800 GiBshort by 3.800 GiB
qwen3vl_32b_minimax_h3_int8_convrot25.277 GiB26.468 GiBshort by 14.468 GiB

Both stream. One streams 10.667 GiB more than the other on every generation, and it is 10.667 GiB more for the machine around the card to hold and move as well. The author of the RTX 3090 write-up reached the same conclusion from the RAM side on a 31,997 MB box, recommending the nvfp4 encoder over the int8 one because "Native execution is not worth 10 GB of extra RAM pressure on a small box." Nobody has timed the two encoders against each other on this card, or on any 12 GB card — the file sizes are the whole of the argument here, and at this capacity they are enough on their own.

Three further things agree, and it is worth being precise about what each is:

  • A Comfy-Org member says the format is not a hardware claim. Asked in discussion #16 whether nvfp4 was Blackwell-only, Kijai answered that it is not, and when pushed added that "it's just used as storage format here, there's nothing hardware specific about that".
  • A 30-series owner reports no penalty and no gain. In the same thread, a commenter posting as progmars reports that he "did not notice any benefits from NVFP4 on 3090 but it was not any worse than int8 either". That is a 24 GB card, where the int8 encoder overruns the card by only 2.468 GiB — a much gentler position than this one — so read it as evidence that nvfp4 costs nothing on Ampere, not as evidence about the offload trade at 12 GB.
  • A 12 GB owner ran it. An RTX 3060 12GB owner posting as LabMike3D reports in the same thread that "you can use the nvfp4 model as a text encoder without any problem and save some extra space (15 GB vs. 24 GB), but that's pretty much all". Different card, same capacity, same conclusion about fit.

The honest counterweight: also in that thread, a commenter posting as V33rGeer argues that "you shouldn't be using the NVFP4 text encoder, as it compromises the coherence of tricky setups", with the escape clause "unless your system physically cannot handle it". He names no hardware anywhere in the thread, and a later reply block-quotes those words back before answering — so they are V33rGeer's opinion about quality, not a hardware report, and do not inherit the replier's machine for them. On this card the escape clause is the entire situation: 26.468 GiB against 12 GiB is not a preference. If prompt adherence fails on a complex reference setup, that is the first thing to revisit, and your prompt is the second.

The int4 shortcut, and why it changes nothing at this capacity. Discussion #35 carries the suggestion from an owner of a different 12 GB card: "why dont you use the int4 version of the qwen3vl? I am also on rtx 3060 12gb + 32 gb ram and am using that." It deserves an answer rather than a dismissal, and the answer is the same on his hardware and on yours — you have the identical 12 GB, so you are both 3.800 GiB short of the encoder stage, and the suggestion is neither more nor less attractive here than it is there. What decides it in both cases is one byte count: the community int4_convrot conversion in Abiray/MiniMax-H3-GGUF is 14,952,506,709 B = 13.926 GiB, a saving of 0.684 GiB rather than the quarter or third the name suggests, because nvfp4 is already a 4-bit format. Taking 0.684 GiB off a 3.800 GiB deficit leaves the encoder streaming on both cards. Two related cautions: the repack publishes no first-party int4 encoder, so every file under that name is a community conversion; and one file in that same folder is named qwen3vl_32b_minimax_h3_nvfp4_awq.safetensors while weighing 27,141,342,223 B — 71 bytes off Comfy-Org's int8_convrot encoder and 10.667 GiB above the nvfp4 file whose name it wears. Verify by size, not by filename.

4. SageAttention: what is settled, what is not, and why neither reaches this card

Two different things get called "SageAttention support", and a prominent open issue makes the subject look riskier here than it is. Take the issue first — it moved four times in five days and its own body is now behind its thread.

ComfyUI issue #15263 is open. Its title names FP8 PV kernels above roughly 160k tokens on sm_120, and its body carries a dated note from its author, posting as AI4VFX, withdrawing his original explanation and his proposed one-line fix. Read that precisely: his explanation was withdrawn, not his finding. He restated the finding more firmly afterwards, telling the person who diagnosed it "I think you've got it right that FP8 PV is the cause", and the issue was retitled to match. That is also why PR #15298, which would have passed low_precision_attention=False for H3, is closed unmerged — on the author's own instruction.

The empirical boundary is solid and you should treat it as fact. On a Blackwell box, on the bf16 checkpoint, with the global flag, he published a token-indexed table: clean at 142k and 151k, noise at 167k, 175k and 186k. His summary — "it's a cliff, not a slope. 151k is clean, 167k is garbage, nothing soft in between."

The mechanism is not settled, and this page does not pretend otherwise. Four explanations have been offered in that thread and three have been withdrawn by the people who proposed them — including a smooth_k theory floated and retracted inside thirty-three minutes. The FP8-accumulation story the title still carries is the fourth, and it was challenged the morning after the retitle. The observation is the issue author's own: having run every kernel mode at the failing length, he found that auto and the explicit ++ mode share pv_accum_dtype="fp32+fp16" and differ only in qk_quant_gran, yet behave differently — "So auto and ++ differ by one parameter and it isn't the PV path." The inference drawn from it belongs to a commenter posting as pepikir, who had diagnosed the original bracket, and who credits that finding to its author: if behaviour tracks the granularity parameter while the accumulator is held constant, then "the PV path isn't the discriminating variable", and a partly-correct frame with a hard edge is "That's the signature of something tile-indexed going out of range past a threshold, not of arithmetic precision." A scale-buffer overrun is the current hypothesis. Name it; do not build on it.

Which is why the argument for this card is a measurement and a ceiling, not a mechanism.

  • Measured, on this architecture. The same pepikir ran both the global flag and the KJNodes node on an RTX 3090 with the stock PyPI wheel, at a fixed seed, and checked the output rather than assuming it — clean both ways, about 1.37× on sampling. He has since pushed that verified-clean ceiling up: "I have it verified clean to 56,120 tokens (1280x736, 243 f)".
  • Unreachable, on any Ampere card. He then computed the number that actually closes it: "at H3's own limits, Ampere tops out at 91,728 tokens" — H3's own MAX_PIXELS area cap at the top of its trained frame range. Against the Blackwell table above that is 61 % of the last clean row (150,960) and 55 % of the first noise row (167,280). His conclusion: "So Ampere cannot reach even your clean row, let alone the crossover." The template this page runs is far below even that ceiling.
  • Supporting, and only supporting. Sage's own dispatch picks the FP16-PV kernel here — "fp16_cuda is only selected for sm80/sm86" — and the stock 1.0.6 wheel ships no FP8 kernel at all, on any card. That is worth knowing, but it is the leg to lean on least, because the contested mechanism is precisely about whether the PV path is the discriminating variable.

Two things this page will not do. It will not hand you a kernel to pin: the body still recommends forcing sageattn_qk_int8_pv_fp16_cuda, and its own thread overtook that — every explicit mode was tried on the Blackwell box and "none of them work here, and I think it changes the conclusion", with fp16_cuda aborting the process and fp16_triton corrupting memory, so "On sm120 there isn't one to pin." The person who proposed the pin withdrew it: "If fp16_cuda aborts the process and fp16_triton corrupts memory on sm_120, there is nothing to pin there". On this card that kernel is simply the default and there is nothing to force — but do not carry the advice sideways to a Blackwell reader.

And it will not tell you the configuration on this page has been cleared. Every sm_120 noise report that names a checkpoint is on the bf16 transformer and text encoder; the only int8_convrot participant in the thread is on sm_86. So the defect has never been tested against the pruned_int8_convrot + nvfp4_awq set installed above, on any card. Untested is not the same as safe — sage transforms activations, not weights, so there is no obvious mechanism by which the checkpoint would matter, and the census tells you nobody has checked rather than that there is nothing to find.

What remains true regardless. H3 does not opt out of sage. ComfyUI's global --use-sage-attention routes through attention_sage in comfy/ldm/modules/attention.py, which imports one symbol — sageattn — from the current PyPI release; attention_sage steps aside only when a caller passes low_precision_attention=False, and at v0.30.2 the DiT's call in comfy/ldm/minimax/model.py is a bare optimized_attention(...) with no such keyword. The flag genuinely puts H3's attention through INT8 quantisation. Render your first clip both ways at a fixed seed and keep the comparison.

pip install sageattention

The path that needs a 2.x build is KJNodes' H3-specific memory-efficient patch, and its blocker is an import rather than a kernel. nodes/ltxv_nodes.py pulls six names out of sageattention.core in one statement — per_thread_int8_triton, per_warp_int8_cuda, per_block_int8_triton, per_channel_fp8, get_cuda_arch_versions and attn_false. Reading the published wheel: sageattention 1.0.6 is the newest release on PyPI, its core.py is 8,530 bytes, it defines exactly two functions (sageattn and sageattn_varlen), and of those six names it carries only attn_false. The statement raises, the architecture probe never runs, and the node reports "sageattention is not new enough version or could not determine CUDA architecture, cannot apply MiniMax H3 Memory Efficient Sage Attention Patch." That failure is identical on every architecture — it is not an sm_86 gate. The real split is the operating system:

  • Windows. Wheels exist. woct0rdho's fork publishes them and lists the silicon they cover: "The latest wheels support GTX 16xx, RTX 20xx/30xx/40xx/50xx, A100, H100, AGX Orin (sm75/80/86/87/89/90/120)."sm86 is on that list, so this card installs a wheel and is done.
  • Linux. Build it. Neither of the two places a prebuilt wheel could come from has one. PyPI's newest sageattention release is 1.0.6, and every file it has ever published — for that version and for all seven before it — is a py3-none-any pure-Python wheel plus an sdist, with no compiled artefact for any platform at all. The one project that does distribute binaries is woct0rdho's fork, which announces its scope in its own title — a "fork for Windows wheels and easy installation" — builds them behind Visual Studio and the Windows SDK, and explains why the PyPI route does not exist: "We cannot publish the wheels to PyPI, because PyPI does not support multiple PyTorch/CUDA variants for the same version of SageAttention."
pip install ninja packaging
CUDA_HOME=/usr/local/cuda-13.2 PATH=/usr/local/cuda-13.2/bin:$PATH \
TORCH_CUDA_ARCH_LIST=8.6 MAX_JOBS=8 \
pip install --no-build-isolation "git+https://github.com/thu-ml/SageAttention.git"

Leave --no-build-isolation in: drop it and pip resolves a second torch into the build sandbox, which is a long download and a broken environment. 8.6 is this card's compute capability and confines the build to kernels it can run. What the build buys on Ampere is the memory-efficient patch, not different kernels: _cuda_archs[0] in {"sm80", "sm86"} in that same KJNodes file casts V to torch.float16 and calls _qattn_sm80.qk_int8_sv_f16_accum_f32_attn, where an sm89 card would quantise V with per_channel_fp8 and dispatch into _qattn_sm89. Same node, different silicon, and the Ampere one is the INT8-QK / FP16-PV variant.

What sage is worth, and where the number comes from. Timings are in Results. The short version: the only published sm_86 measurement was taken on a different Ampere card with twice this one's capacity, which makes it a bound on the compute side of the ledger rather than a prediction for yours. Read it there before planning around it.

5. Load the official template

In ComfyUI's Template Library, take MiniMax H3 Text to Video; dragging video_minimax_h3_t2v.json onto the canvas does the same thing. Its loaders name exactly the four files downloaded above and nothing else. The ComfyUI tutorial documents this template alongside the I2V and R2V variants, which load the same encoder and VAEs through a different diffusion checkpoint.

Running

Start ComfyUI with the offload flag. On a 32 GB machine the default launch is the failure case rather than the baseline.

python main.py --disable-pinned-memory --use-sage-attention

Host RAM, not VRAM, is what usually ends an H3 run here

ComfyUI page-locks host memory to speed transfers to the GPU. The ceiling for that, MAX_PINNED_MEMORY, is 90 % of your RAM on Linux and 40 % on Windows — but the per-model request is pinned_hostbuf_size(size), which evaluates to min(size, MAX_PINNED_MEMORY) * 2, i.e. double the file. For the 19.530 GiB transformer that is a request for 39.060 GiB of page-locked host memory, which a 32 GB machine simply does not have. Pinned pages can be neither swapped nor reclaimed, so when the machine runs out, the kernel's only remaining move is to kill the process. The author of a 31,997 MB RTX 3090 box states the consequence plainly: "You cannot page out pinned memory." — adding swap does not help until the flag is set.

Two people have posted numbers for what that costs, on other cards, and between them they bracket the problem.

  • What the default launch asks for. On the repack's discussion #6, a user posting as UdonJP ran one job on an RTX 5070 Ti with this exact four-file set and changed only the startup flag, under the heading "One startup flag changes the RAM requirement by ~3.6x." — ComfyUI's resident-set peak was 45.4 GiB with no flags. One person, one machine, and note that the flag he was measuring against is --fast-disk rather than the one recommended here. Take from it only the baseline: the default launch wants around 45 GiB, and a 32 GB box does not have it.
  • What the fix does on an actual 32 GB machine. The RTX 3090 write-up, on a 31,997 MB box, reports 29,866 MB of host RAM and a kernel OOM-kill on default flags against 7,508 MB and a completed 15-second clip with --disable-pinned-memory set. Different card, same transformer — and since the pinned request is sized off the DiT rather than off your VRAM, that is exactly the part which transfers to a 12 GB machine.

What the flag costs you in speed is unmeasured, and the mechanism says the answer depends on your RAM rather than on your card. Page-locking governs how the weights reach the GPU, not where they live in between: on a machine with room to keep the 42.47 GB weight set in page cache, dropping the pin changes the transfer path and not the source of the bytes. A 32 GB machine has no such room, so the streaming this card cannot avoid starts arriving off the SSD instead. Nobody has published how large that penalty is at this tier, on this card or on any other. Take the trade regardless — the alternative on 32 GB is not a slower render but a killed process — and put the weights on the fastest NVMe you own rather than a SATA drive. With 64 GB you keep both the flag and the page cache, and this paragraph does not apply to you.

The drive is not being asked for a little. At least 8.721 GiB of the transformer is off-card on every sampling step and has to be read back from somewhere each time, twenty times over at the template's step count, and nobody has published the total a 12 GB card actually re-reads per generation. That is why --fast-disk, which comfy/cli_args.py describes as "Prefer disk-backed dynamic loading and offload over unpinned RAM.", is a reasonable second flag on a fast NVMe and redundant once pinning is off. --lowvram is not the answer here whatever its name suggests — the same file's help string for it reads "Doesn't do anything if dynamic vram is enabled.", and dynamic VRAM is precisely what is carrying this run.

Set the canvas down — it is the biggest lever you have here

Queue the template unchanged first, and know what "unchanged" resolves to, because the generation node's stored widgets disagree with what runs. Its ResolutionSelector sits on 16:9 at 0.4 megapixels, snapping to multiples of 32, and feeds the generation node through connected width and height inputs. A wired input always wins over a stored widget value, which is why the 1344×768 you can see in the node never gets anywhere near the sampler. Work it through and the selector resolves to 864 × 480: sqrt(0.4 × 1024² / (16×9)) is 53.9695, which each axis then rounds to its nearest multiple of 32. The frame count snaps to a 17k+5 grid at 24 fps, so a 5-second request becomes 124 frames; the node's own tooltip gives the trained range as 124-362.

megapixels16:9 outputwhat it is
0.4864 × 480the template's shipped default
0.5960 × 544one step up
0.981344 × 768the generation node's stored default, and H3's MAX_PIXELS
1.01376 × 768one row above the model's own cap

BASE_SHORT_EDGE is 768 and MAX_PIXELS is 768 * 1344 in comfy_extras/nodes_minimax_h3.py, so 0.98 MP is the native canvas — the RTX 3090 write-up's summary that the "Practical canvas ceiling is 1344x768" is a statement about the model, not about your card. Your card's ceiling is lower, for a different reason: cost. Every extra token is paid for twice here, once in compute and once in transfer, because the transformer is not resident — and this card is under maximal offload pressure at every canvas, so the second half of that bill never goes away. Nobody has published a scaling curve for the 12 GB tier, but an RTX 3060 12GB owner — same capacity, same streaming regime — put the practical version of it in discussion #30: "render times grow exponentially as the resolution, video length, and the number of steps increase". Step the canvas up one row at a time and re-time it rather than extrapolating.

Frame count is the same lever from the other side. On an RTX 3090 — a card that holds the denoise pass resident, which this one does not — 124 frames sampled at about 12 s/step against about 67 s/step at 362 frames, and that author's conclusion generalises even though his timings do not: "Extrapolate by frames superlinearly, never by a flat per-step figure."

Finished clips arrive under ComfyUI/output/video/, already muxed to MP4 with the generated stereo track inside the container.

What sm_86 subtracts, and what the 384-bit bus does not buy

Two of the three quantisation formats in these files are emulated here

pick_operations in comfy/ops.py probes the device once and turns each failed probe into a disabled format, then prints the split at startup. On this card supports_fp8_compute() returns False — it passes compute capability 8.9 and above, and 8.6 is below the line — and supports_nvfp4_compute() requires major version 10. So float8_e4m3fn, float8_e5m2 and nvfp4 all land on the emulated side, leaving int8_tensorwise as the one format used by these weight files that keeps a native path. An RTX 3090 owner records the exact line an Ampere card prints:

Native ops: convrot_w4a4, int8_tensorwise , emulated ops: float8_e5m2, float8_e4m3fn, nvfp4, mxfp8

Two consequences follow, and they point in opposite directions.

The FP8 transformer is not a fork you have. There is a fourth diffusion file in the repack, minimax_h3_fl2va_pruned_fp8_scaled.safetensors, at 20,958,205,608 B = 19.519 GiB. That is 11.61 MiB under the int8 build installed above — near enough a free swap on memory, and on an Ada card a genuine experiment. Here it is not one. When a layer's format is in the disabled set, comfy/ops.py sets _full_precision_mm = True, and the forward pass builds its _use_quantized decision with not self._full_precision_mm as a conjunct. The file loads, occupies the same space, and dequantises. There is nothing to try.

Emulated does not mean unpacked, and that is why the encoder choice above survives. The RTX 3090 write-up states the same mechanism from the observed side: "Weights stay packed at their quantised size; only speed suffers." The nvfp4 encoder is 14.610 GiB on this card exactly as it is on a 5090. And in this particular file it is not even losing speed to emulation, because it declines the accelerated path on its own: its header carries 351 comfy_quant descriptors, of which 350 set full_precision_matrix_mult and one — on model.embed_tokens — is int8_tensorwise, and the file ships zero input_scale tensors, which are exactly what an FP4 matmul would need. Hardware support is a property of the format; use is a property of the file. That is the technical content behind Kijai's "storage format" line in Installation step 3.

The transformer's fast path is not architecture-gated

State this one positively too, because it is easy to over-generalise from the encoder. Every one of the 200 quantised layers in minimax_h3_fl2va_pruned_int8_convrot.safetensors carries the identical descriptor {"format": "int8_tensorwise", "convrot": true, "convrot_groupsize": 256}, and there is no full_precision_matrix_mult opt-out anywhere in that file. int8_tensorwise never enters pick_operations' disabled set on any NVIDIA card — you can see it on the native side of the log line above. So "the file dequantises anyway" is true of the text encoder and false of the transformer. What actually gates the transformer's kernels is Installation step 1: a cu130 torch build and a working comfy-kitchen import.

The bus is wider. Nobody has measured what that is worth here

NVIDIA's 30-series product page gives this card 10,240 CUDA cores, a 1.67 GHz boost clock, 12 GB of GDDR6X and a 384-bit memory interface at 350 W. The 12 GB card that produced every published H3 timing at this capacity, the RTX 3060, is listed on NVIDIA's own page with 3,584 CUDA cores, 12 GB of GDDR6 and a 192-bit interface at 170 W. Neither page publishes a bandwidth figure in GB/s, so this one does not assert one — the bus is twice as wide and the memory type is faster, and that is as far as NVIDIA's numbers go.

Whether any of that shows up on this workload is unmeasured, and the mechanism argues for caution. The resource that decides an H3 run here is not on-board bandwidth: 8.721 GiB of the transformer is not in that GDDR6X at all on any step, and it arrives over a PCIe link both cards share. On-board bandwidth serves the resident fraction and the activations; the shortfall is served by the host. So the direction is not in doubt — more cores and a wider bus cannot be slower — but the magnitude could be a long way below what a 2.9× core ratio suggests, and nobody has published a pair of runs that would tell you. If you own both, that comparison through /contribute would be genuinely new.

Results

  • Speed: our catalogue holds no benchmark for this pair — /check/minimax-h3/rtx-3080-ti returns verdict: unknown with an empty benchmark list — and this round found no published MiniMax H3 timing taken on an RTX 3080 Ti anywhere. The repack's discussion list was enumerated rather than searched — all 37 threads fetched individually, 222 message bodies — and not one of them mentions this card, under 3080, 3080 Ti or GA102; a ComfyUI issue search returns exactly one RTX 3080 Ti report, and it is about a different model on ComfyUI v0.26.0 (see Troubleshooting). Every number below therefore names the card it was taken on, and none of them is a prediction for yours.

    What the 12 GB tier looks like elsewhere. An RTX 3060 12GB owner reported in discussion #30: "RTX 3060 12GB | T2V | 1376x768 | 24 steps | 3 sec (20 min was crazy!)" — twenty minutes for three seconds, one row above the model's own canvas cap. That card has 3,584 CUDA cores against this one's 10,240 and half the memory bus, at the same capacity and therefore in the same streaming regime, so it is best read as the slow end of the tier rather than as an estimate.

    What sage is worth on Ampere, measured on a bigger Ampere card. A commenter posting as pepikir published a controlled pair on ComfyUI issue #15263, with the setup line "RTX 3090 (sm_86), ComfyUI 0.30.1, torch 2.11.0+cu130, sageattention 1.0.6 (PyPI, pure-Triton wheel), minimax_h3_fl2va_pruned_int8_convrot.safetensors, 864×480, 124 frames, 20 steps, res_multistep/simple, BasicGuider, fixed seed." — the stock template on the exact checkpoint installed here. His table, whose own column is headed sampling, gives 9.00 s/it with no sage against 6.50 s/it with ComfyUI's --use-sage-attention and 6.57 s/it with the KJNodes node, on the stock PyPI wheel: about 1.37× either way, with "Zero using pytorch attention instead fallbacks in either run, so sage was genuinely active both times." Two limits on reading that across. It is an RTX 3090 with 24 GB, where the denoise stage is resident and the sampler is compute-bound; this card streams at least 8.721 GiB per step, and a speedup to the compute half of a run does not scale one-for-one when transfer is sharing the critical path. And it counts sampling only — text encode, VAE decode and the model loads sit on top, and on a 12 GB card the loads are not incidental.

  • VRAM usage: the binding figure is the denoise stage's 20.721 GiB — the transformer's 19.530 GiB of int8 weights sitting on top of a 1.191 GiB inference reserve — set against 12 GiB of GDDR6X. Residency therefore tops out at 10.809 GiB and no fewer than 8.721 GiB are in flight on every step. Both numbers come from the on-disk byte counts and ComfyUI's own constants; neither was measured on hardware, by us or by anyone. The nearest measured readings are a tier up. On the repack's discussion #6 a user posting as UdonJP, running this same four-file set on an RTX 5070 Ti — 16 GB of VRAM, 125 GB of host RAM, ComfyUI v0.30.1 — reports "VRAM peak was 14,197 MiB for 30 s @ 640x480 and 14,437 MiB for 5 s @ 1344x768". That is one person's pair of readings from one machine rather than a benchmark, and he states his own scope in the same post: no BF16 build tested, and "it is inference from a 125 GB box." Take from it only the thing it settles cleanly, which the arithmetic above already reached on its own: both readings exceed a 12 GiB card's entire capacity, the lower of them by 185 MiB, so a card of this size cannot be holding what a 16 GB card was measured holding. That it does not fail anyway is the point of the page. Live data, when it exists, appears at /check/minimax-h3/rtx-3080-ti.

  • Quality notes: the model's documented weakness is faces at distance, and it is a property of the model rather than of your memory. It is what the RTX 3060 owner cited earlier opened discussion #30 to complain about: "MiniMax heavily distorts faces on wide shots. Distortions happen regardless of input res (even at 720p, very bad). Close/medium shots look fine!" then re-tested at a higher canvas and more steps and found the artefacts unchanged. Compose close and medium, not wide. EasyCache, the accelerator you will be pointed at first, comes with one published complaint and no published defence: a commenter in that thread says "Using 'EasyCache' node also degrades the quality of the final result.", and nobody has posted an A/B of the node on a 12 GB card, or on this card at any capacity. Treat it as untested here, run your own comparison at a fixed seed before you leave it switched on, and judge it by looking at the clip rather than by a difference metric.

For the full benchmark data, see /check/minimax-h3/rtx-3080-ti.

Optional: the 8-step Turbo path

Step count is the largest single lever on any card, and it is larger here than on a card that holds the transformer resident, because each step you remove also removes a full pass of streaming. A community distillation adapter, larryvrh/MiniMax-H3-Turbo-Lora, with its own node pack at Larryvrh/ComfyUI-MiniMax-H3-Turbo, brings sampling down to as few as 4 steps — though at the revision linked there its author recommends 6 to 8 for the current v4 checkpoint, and describes 4-step output as smearing on large fast motion. Read that card at a pinned revision too; it was rewritten twice on 7 August alone.

The only 12 GB-class timing published for it is an RTX 3060's. Its author writes in discussion #35: "Everything was tested on an RTX 3060 12GB. Rendering a 5-second video at 864x480 resolution with Turbo at 8 steps took 4.5 minutes." Note what else that run changed, because it is three things and not one:

  1. the 8-step Turbo LoRA, driven by a third-party node pack;
  2. Kijai's experimental minimax_h3_video_vae_int8_convrot.safetensors, which is not in the official repack;
  3. and therefore a ComfyUI newer than the v0.30.2 tag this page installs — that VAE arrived in PR #15334, merged after the tag. grep -i convrot comfy/sd.py returns nothing at v0.30.2 and returns the int8+convrot decoder branch on master.

Three non-stock components, one run, one card that is not this one. A conversion of the same adapter targeting the pruned checkpoint exists and is the build you would reach for here — its card at revision 69e50f16b8 describes the files as compatibility conversions that let the adapters load with ComfyUI's built-in MiniMax-H3 LoRA loader on the pruned model, which is what this page installs — but it credits larryvrh for the weights, the training and the distillation, so it is the same measurement wearing different packaging, not a second one. Pin that revision when you read it: the card has been rewritten three times in two days, most recently on 8 August, and now carries a further v4 step-600 checkpoint it marks as recommended. Nobody has published a 12 GB timing for that one. Take it if you are content to run pre-release parts and re-render when one of them changes; do not put it on a delivery date. An adapter's own permissive tag also does not lift the base weights' territorial restriction.

Troubleshooting

The process is killed outright, or MemoryError fires during the model load

System RAM, not VRAM, is the usual ending — which is why --disable-pinned-memory is in the launch line above rather than down here. If ComfyUI still dies during the model load with the flag set, grep the startup log for Enabled pinned memory: if that line is present, the flag did not take. Adding swap does not help on its own, because pinned pages cannot be paged out, and the RTX 3090 write-up separately measured --disable-smart-memory, --high-ram, --reserve-vram and --cache-lru and found each made this failure mode worse rather than better.

There is a duller second cause when the MemoryError comes out of UNETLoader specifically, and it is worth eliminating first because it is free: a truncated download. One reporter on this repack worked it out only after re-fetching — same byte count, different hash.

UnicodeDecodeError from the text-encoder load, then "Unknown quantization format"

Reported against this recipe's exact encoder file in ComfyUI issue #15400, and reported from an RTX 3090 — the same architecture as this card, so it is worth naming rather than dismissing. Check your own artifact before inheriting the symptom. The report's premise is that some comfy_quant tensors in the file contain only NUL bytes, specifically that model.embed_tokens.comfy_quant is a 29-byte all-zero placeholder that sends json.loads down a UTF-32 detection path. Read out of the published file over a byte-range request this round, those 29 bytes are not zeros: they decode to {"format": "int8_tensorwise"}. The reporter was also on a master checkout rather than a release tag, and on CUDA 12.9 rather than 13. So pin the release tag as in Installation step 1, confirm +cu130, and re-hash the download before changing anything — a size-matching truncation presents identically and is far more common.

Generation is far slower than the numbers on this page

Grep the startup log for Failed to import comfy_kitchen. A failure there takes the int8 convrot fast path with it and leaves ComfyUI otherwise healthy: the queue runs, the video appears, and the only trace is a single line scrolled off the top of your terminal. The same applies to a torch build below cu130, which prints its own warning and then continues. On a card whose entire performance story is offload, either one turns a slow run into a much slower one. The positive check is the Native ops: line quoted above: int8_tensorwise and convrot_w4a4 belong on the native side.

The one RTX 3080 Ti report in the ComfyUI tracker is about this backend, and it is worth knowing why it does not transfer. Issue #14719 describes repeated system freezes on an RTX 3080 Ti with the comfy-kitchen CUDA backend enabled, cleared by disabling it. It is a different model's workflow, on ComfyUI v0.26.0/v0.27.0 with comfy-kitchen 0.2.10 — several releases below what v0.30.2 installs, and 0.2.10 is the version separately reported to fail importing the convrot layout in the first place. Its environment line also states "32Gb VRAM" for a 12 GB card, so read it carefully. If you do hit host-level freezes, disabling the CUDA backend is the reported workaround, and on H3 it costs you the transformer's fast path — that is a real trade, not a free fix.

The GGUF transformers still will not load on stock ComfyUI

Somebody will point you at a pruned Q4 GGUF of the transformer — they circulate at roughly 10.6 GiB, which is the first weight file in this whole story that would actually fit in 12 GB, so the appeal is obvious. With the stock loader they are a dead end, for a reason you can check yourself: ComfyUI-GGUF/loader.py gates diffusion models against an IMG_ARCH_LIST of flux, sd1, sdxl, sd3, aura, hidream, cosmos, ltxv, hyvid, wan, lumina2 and qwen_image — nothing for H3, unchanged as of this writing, and issue #471 requesting support is still open. The text encoder is the exception: qwen3vl is on the same file's TXT_ARCH_LIST, which is why encoder GGUFs do load.

Your render came out as noise and you have sage switched on

Installation step 4 has the scoping; this is the operational version. The one documented sage failure on H3 is length-gated, and the budget is counted in tokens rather than seconds, so check the count rather than the clip length.

Two conventions are in circulation and they disagree on absolutes. The thread counts ceil(frames/4) × (W/32) × (H/32), and every row it publishes reproduces from that formula exactly; ComfyUI's own H3 node computes latent frames differently, video_latent_t(f) = ((f - 5) // 17) * 5 + 2 in comfy_extras/nodes_minimax_h3.py, which runs about 18 % higher. The disagreement does not reach the question you are asking, because the two share an identical spatial term and differ only by a near-constant temporal factor, so a ratio between two jobs survives it. Count in the thread's convention, since that is the one its own datapoints are in: the template here is 12,555 tokens, and the largest job H3 will accept at all — its MAX_PIXELS area cap at the top of the trained frame range — is 91,728, against the Blackwell rows of 150,960 clean and 167,280 noise.

The conclusion is not marginal: the biggest job this card can be asked to render sits at 55 % of the lowest token count at which anyone has seen the defect, and the template sits at 8 % of it. If your output is noise at these settings, sage is very unlikely to be the cause — but it is still the cheapest single variable to eliminate, so drop the flag and re-render at a fixed seed before looking further. It is worth eliminating properly rather than living with, because H3's attention share is "roughly 55% of sampling at 480p/5s, considerably more at 720p or 15s".

Do not respond by pinning an explicit kernel mode. That advice is in the issue body and its own thread has overtaken it — see Installation step 4.

Do not route the decode through VAEDecodeTiled

H3's video VAE already tiles and chunks internally, and comfy/sd.py sets handles_tiling = True for it, so routing its packed audio+video latent through the tiled-decode node is at best a no-op and at worst an error. Leave the template's own VAEDecode and VAEDecodeAudio pair in place; they are already the right pair for this VAE.

You want 2K output

Not locally, today. H3-Regenerate-2K is not part of the open-weights release — the module directory does not exist in the repository — and the official route to 2K is to feed your local 768p result back to MiniMax's hosted API, a call that falls under the same territorial licence.

Nothing here matches your problem

Take runtime errors to ComfyUI/issues, anything wrong with the graph itself to workflow_templates/issues, and sage-patch failures to ComfyUI-KJNodes/issues. And if you get a clean run on this card, a timing sent through /contribute would be the first one anybody has published for MiniMax H3 on an RTX 3080 Ti — worth more to the next reader than every derived number above.

common questions
How much VRAM does MiniMax H3 (Hailuo 3) need?

About 12 GB — the minimum this recipe targets.

Which GPUs is MiniMax H3 (Hailuo 3) tested on?

RTX 3080 Ti (12 GB).

How hard is this setup?

Advanced — follow the steps above.