How-To
HOW-TO SEP 29, 2026 ~9 MIN READ

Qwen3.8-Flash-Next on a 128 GB Box: How to Leave 51B of It on the SSD

180B parameters and 128 GB of memory — and it fits. A fifth of the model is a lookup table that only ever gets read, never multiplied, so it can sit on NVMe. This is the hands-on companion to our review: the exact llama.cpp command, the memory math that proves it fits, and the three routes to get there.

The Short Version

You run it with two flags. -lm mmap and -ot "per_layer_token_embd=CPU". They pin the 51.2B N-gram table off the GPU and let the OS page cache serve rows straight from NVMe as they're looked up. Decode barely notices. The model is not fast — roughly 22 tok/s single-stream — but it's a frontier-class open model on a box that costs a few thousand dollars, and the trick generalises.

~180BTotal params
51.2BTable on SSD
103.7 GiBQ4 model file
~77 GiBMust be resident
6 GiBKV at 262K ctx
~22tok/s single

01 The One Idea That Makes It Fit

Qwen3.8-Flash-Next has ~180B parameters, but they aren't all the same kind. 128.8B are compute — the MoE experts, attention, Gated DeltaNet — and they're read densely, every token, so they must be resident. The other 51.2B are a single tensor:

per_layer_token_embd.weight shape [160, 320001536] # 160 × 320,001,536 = 51.2G elements — 28% of the model, one tensor

the N-gram / PLE embedding table — a second memory layer, not a weight matrix

A weight matrix in a matmul is read in its entirety every use — if it isn't resident, every token pays the full transfer and speed collapses to storage bandwidth. An embedding table is different in two ways that make offloading free:

  • Sparsely accessed. Per token the model gathers ~16 rows out of 320,001,536. It never touches the other 99.99995% for that token.
  • Deterministically addressed. The rows are known from the token ids (via an n-gram hash) before the gather runs — a lookup, not a computation over the tensor. So the per-token traffic is a handful of tiny reads, not a 26.8 GiB stream.

Reads like that are exactly what an OS page cache over NVMe is good at. Qwen's own tech report makes the point explicitly: the N-gram vocabulary can be scaled up precisely because the resulting table can be served from off-accelerator storage. That's the whole trick, and it's why the rest of this article is mostly bookkeeping around two flags.

02 The Memory Math

At the UD-Q4_K_XL quant the model file is 103.7 GiB (4 shards). Here's where each byte ends up on a 128 GB box:

PortionSizeWhere it lives
Compute weights (128.8B)~76.9 GiBResident, in unified memory
N-gram / PLE table (51.2B)~26.8 GiBOn NVMe, served via page cache
Process RSS~1.4 GiBWeights are mmapped, so almost nothing is process-private

source: 0xbakeer/qwen38-flash-next-spark, docs/how-it-works.md, measured on a 121 GiB-usable GB10

The 26.8 GiB is simply 103.7 − 76.9, and it matches the size of the sequential read that warms the whole table. Steady state measured: ~95 GiB used overall, ~26 GiB in the page cache (the table, once touched), and that's it. The margin is what buys the long context, because the KV cache is shockingly small.

Why 262K context costs only 6 GiB There are 48 layers, but only 12 use full attention with a growing KV cache — the other 36 are GDN-style layers whose state is constant-size regardless of context. The full-attention layers use GQA with just 2 KV heads. Net: ~24 KB per token, so the entire 262,144-token window is 262,144 × 24 KB = 6 GiB. That's why you can enable max context by default instead of trading it away. One catch: KV must stay f16 — quantised KV aborts on this architecture.
Minimum to runRAMWhy
1-bit quant75 GBSmallest. Table held at 4-bit floor — random-access tables degrade under heavy quant
2-bit79 GB
Q4 (measured recipe)~100 GB usable76.9 GiB resident + room for the page cache. This is the 128 GB path

unsloth quant docs · 0xbakeer recipe preflight (warns below ~100 GiB)

03 The Exact Command

This is the whole trick, verbatim from the reference recipe that all the published numbers were measured on. Build a current llama.cpp first — qwen4exp support merged upstream on Aug 27, 2026 (PR #27742), so anything older dies with unknown model architecture: 'qwen4exp'.

llama-server \ -m model/gguf-model-q4_K_m.gguf \ -lm mmap \ -ot "per_layer_token_embd=CPU" \ --n-gpu-layers 999 \ --ctx-size 262144 \ --parallel 2 \ --spec-type ngram-mod \ --temp 1.0 --top-p 0.95 --top-k 20 \ --host 127.0.0.1 --port 30000

two flags do the offload; everything else is standard serving config

  • -lm mmap — memory-map the model so the table's pages are only faulted in as rows are actually gathered, rather than being read into RAM up front.
  • -ot "per_layer_token_embd=CPU" — pin that one tensor to the CPU backend so it's never copied to accelerator-resident memory. With mmap, it stays a file the OS serves on demand.
  • --n-gpu-layers 999 — push the compute layers to the GPU / unified memory. The one tensor you just pinned stays out.
  • --ctx-size 262144 — enable the full window. It's only ~6 GiB, so there's no trade-off.
  • --parallel 2 — slots. llama.cpp divides ctx-size across them, so this is a standing claim on context (2 → 131,072 tokens each), not a free concurrency knob. 2 costs nothing at one caller and is worth ~1.25× under load.
  • --spec-type ngram-mod — speculative decoding that drafts spans from context repetition. It's exact (the target verifies every token, so output is unchanged), free (no draft model, no memory), and a big win when you're rewriting text that already exists. A no-op on free-form prose. Disable with --spec-type none.
Before you run it Swap must be off (sudo swapoff -a). You want cold table pages evicted from the page cache, never resident compute weights pushed into swap — that would destroy the whole arrangement. And keep the model file on NVMe (not a SATA SSD); the read latency only hides behind compute when the drive can stream ~1 GiB/s.

04 The Three Routes

Same idea, three ways in. Pick by hardware and how much setup you want to do.

RouteBest forHow the table is served
DIY llama.cpp Any Linux box, 75+ GB RAM, one GPU or none The two flags above. -ot per_layer_token_embd=CPU + -lm mmap. The page cache does the rest.
0xBakeer Spark recipe DGX Spark / GB10, 128 GB, want it turnkey ./run.sh edit serve or ./run.sh longctx serve. Wraps the same flags, pins the exact commit, serves an OpenAI API on :8000.
sglang-ssd-stream NVIDIA datacenter (RTX PRO 6000 / N150), max headroom FP8 table to a read-only sidecar file, io_uring concurrent reads, conversion on a side CUDA stream. The 64 MiB-RAM measurement below.

0xbakeer/qwen38-flash-next-spark (MIT) · sglang-ssd-stream (Apache-2.0) · llama.cpp PR #27742

Route A — the turnkey DGX Spark one

The most-documented path. One repo, two recipes that are genuinely good at different things:

git clone https://github.com/0xBakeer/qwen38-flash-next-spark.git cd qwen38-flash-next-spark # coding agents that rewrite files → edit (~105 GB) ./run.sh edit setup ./run.sh edit serve # chat, reasoning, long documents → longctx (~126 GB, vLLM + NVFP4 + MTP) ./run.sh longctx setup ./run.sh longctx serve

both answer an OpenAI-compatible API on :8000/v1 — so Open WebUI, coding agents, your scripts all just work

Not sure which? Start with longctx — it's the more even performer and its fast document reading is the first difference you'll feel. The two share the GPU, so only one runs at a time.

05 The Numbers

The honest story: the trick removes the memory obstacle; it doesn't make 180B fast. Here's what "running it" actually feels like.

DGX Spark (128 GB, GB10), by task

WorkloadEditing recipeLong-ctx recipe
Rewrite a file, one change88 tok/s39
Fix a bug in a file4635
Write new prose2832
Read a 128K-token document (prefill)~7 min~56 s
Concurrent requests2 (half context each)16

0xbakeer/qwen38-flash-next-spark, docs/measurements.md · speeds are meaningless without the task attached

Read that column for editing and the spread is the whole architecture: ngram-mod drafts from your prompt, so when you paste a file and change one thing, almost every answer token already exists and it leaps ahead 60 tokens at a time. Ask it to write something new and there's nothing to copy, so it falls back to ~28. A speed figure for this model is meaningless without the workload next to it.

Why the SSD doesn't show up on a GPU

RTX PRO 6000 (96 GB), NVFP4RAM usedDecode
Table in RAM47.68 GiB148.5–156.2 tok/s
Table on SSD (sglang-ssd-stream)~64 MiB164.7 tok/s · 47.6 GiB freed

sglang-ssd-stream public benchmarks, matched 1,024-token completions · independent community measurement

Move a 47.6 GiB table to disk and it got faster, using ~64 MiB of RAM. On the GPU, the 160-byte random reads hide entirely behind compute. The same physics holds on a CPU box — decode time is dominated by reading the activated compute weights out of ~273 GB/s unified memory, and the few-KB table reads largely hide behind that.

06 Skip the Warming

The most-repeated tip in the community is to "warm" the table — read it sequentially once so the hot rows land in the page cache. On the current build, it does nothing, and you shouldn't bother.

An early measurement claimed +42% on copy-heavy work after a 27-second warm. It was retracted. Re-measured on the current build with CUDA graph capture engaging, residency changed nothing: prose ran 27.8 tok/s at both 17.7% and 58.1% cached, and file reproduction was 88.5 cold vs 86.2 warm — a difference inside the noise. A third-party box (six vLLM runs) confirmed the floor: identical runs differ by ~7%, which is bigger than any warm-vs-cold gap. The recipe ships WARM=0 for this exact reason.

Why it stopped mattering Warming only helps when page faults dominate the per-token cost. Once CUDA graph capture engages, the cost the faults used to sit on top of is much smaller, so residency stops being the bottleneck. The table being on NVMe at all is, for all practical purposes, free — which is the point of the whole article.

07 What It Does Not Solve

  • It doesn't make 180B fast. ~22 tok/s single-stream on the Spark at Q4. Speculative decoding is where the headroom is, not the table location.
  • Prefill is a clock problem. A Strix Halo box handled a 201,647-token prompt in 17.3 minutes to first token. Long context stopped being a memory wall — now it's just slow to chew through.
  • Thinking burns tokens you don't see. The model thinks before it answers, and in one measurement 86% of generated tokens were reasoning. Turning thinking off got the same answer in 15 s instead of 55 — not faster tokens, far fewer of them. Add {"chat_template_kwargs": {"enable_thinking": false}} for everything but hard reasoning and maths.
  • 24 GB cards don't qualify. Even at 1-bit the floor is 75 GB. This is a 96–128 GB unified-memory model, full stop.
  • QSA is approximate by design. Sparse attention can diverge slightly on ~3% of positions past the 8K sparse-attention budget. Full context works; don't assume bit-exactness at the edge.

08 The Bottom Line

  • 128 GB unified memory (DGX Spark, Strix Halo, big DDR5 tower + NVMe): this is your model. Two flags, swap off, full 262K context for 6 GiB. The first frontier-class open model that was actually designed for this tier.
  • 96 GB: fits at Q4, tight on the KV headroom. 75 GB at 1-bit if you need the margin.
  • A single 24 GB GPU: no. Wrong tier — keep a dense 27B there. This needs unified memory, not VRAM.
  • NVIDIA datacenter (RTX PRO / N150): use sglang-ssd-stream, not llama.cpp — the io_uring + FP8 path is what gets you to 64 MiB of RAM and the ~165 tok/s figure.
  • Everyone: skip the table-warming, turn thinking off for most requests, and attach the workload to every speed number you quote.
Caveats All speeds and the memory arithmetic are from community measurements (0xBakeer Spark repo, sglang-ssd-stream, abliter8-ai Strix Halo), not vendor benchmarks — treat them as representative, not absolute. The +42% warming claim and its retraction are reproduced here exactly as the repo documents them. The model carries the Qwen Community License, which has its own conditions.
Sources: Qwen3.8-Flash-Next technical report (Aug 2026) · 0xBakeer/qwen38-flash-next-spark (README, how-it-works.md, measurements.md, inference-atlas) · llama.cpp PR #27742 (qwen4exp, merged Aug 27, 2026) · sglang-ssd-stream public benchmarks · Unsloth documentation & quant tables · abliter8-ai Strix Halo deployment.

This article was drafted with AI assistance and reviewed by a human editor.

ZVHH — AI Tools & Software Reviews © 2026 HomeAgent feed