Benchmark · Apple M4 Max 128 GB · October 2026
Five local inference servers, the same model and its Swift 1.5 fine-tune, contexts from 8K to 1M tokens. I measured what you wait for in a real agent session, not only tokens per second.
Result: Splash 1.4.0 with the unsloth UD-IQ4_XS GGUF has the shortest agent turn at every context size: 6.8 s at 128K, 7.3 s at 512K, 10.5 s at 1M. It is the only server that reached 1M. Its cost: a change halfway in the history prefills the whole prompt again. If your agent edits, compacts or forks the history often, use mlx-serve 26.10.3 with the ddalcu iQ-MLX 4.7 bpw quant (8.9 s at 128K, 14.5 s at 512K). Conclusion · commands.
Goal
The best stack for Qwen3.8-Flash-Next as a daily driver on one Mac Studio (M4 Max, 128 GB): a 125B mixture-of-experts with 6B active parameters and a native context of 262K tokens.
Weights
Each server runs the pack its author publishes, in its own format, 4.7 to 5.97 bits per weight (table). The results compare server + quant pairs, not servers alone.
Precision
A personal test, not a lab benchmark: one machine, one test prompt, 1 to 3 runs per point. Small differences can be run-to-run variation.
The first five rows run the base model; the last two run the Swift 1.5 fine-tune. Same test prompt, same sampling (temperature 1.0, top_p 0.95, top_k 20, reasoning effort xhigh, max 4,096 output tokens). All use speculative decoding and a prefix cache; they differ in where the cache lives and in how they handle the memory limit. Why these servers and when each ran: section 8.
| Server | Weights (quant) | Disk | Prefix cache lives in | Speculative decoding | Largest context on 128 GB |
|---|---|---|---|---|---|
| mlx-serve 26.10.3 MLX server by ddalcu | ddalcu iQ-MLX 4.7 bpw | 107 GB | RAM (16 GB) + disk (100 GB) | MTP + n-gram lookup | 512K (YaRN 2.0 + 4-bit KV cache) |
| oMLX 0.7.0 MLX server by Jundot | Jundot oQ4e-mtp (5.97 bpw) | 132 GB | paged, spills over to SSD | MTP | 262K (no YaRN support) |
| MTPLX 2.12.2 MLX server by Youssofal, ships its own quant packs | MTPLX Optimized-Speed (5.43 bpw) | 120 GB | session bank in RAM + SSD | MTP (depth 3) | 128K, only with --memory-limit max |
| ds4 (antirez, build 0aaea5a) antirez's inference engine, Metal backend, GGUF weights | antirez Q4 GGUF | 177 GB | on disk (100 GB) | MTP (1 draft token) | 512K (YaRN 2.0) |
| Splash 1.4.0 Inco AI's native Metal engine, GGUF weights only | unsloth UD-IQ4_XS GGUF | 94 GB | RAM (8-bit KV cache) + SSD (32 GiB) | DFlash2 draft model | 1M (YaRN, the KV past ~860K tokens on SSD) |
| Splash 1.4.0 / Swift 1.5 Inco AI's native Metal engine, GGUF weights only | ukisai Swift 1.5 IQ4_XS GGUF | 98 GB | RAM (8-bit KV cache) + SSD (32 GiB) | DFlash2 draft model | 1M (YaRN, the KV past ~860K tokens on SSD) |
| mlx-serve 26.10.3 / Swift 1.5 my daily driver: the Swift 1.5 fine-tune in MLX | Dankpaws Swift 1.5 MLX 4.7 bpw | 99 GB | RAM (16 GB) + disk (100 GB) | MTP + n-gram lookup | 512K (YaRN 2.0 + 4-bit KV cache) |
Agent turn time = the wait from sending a tool result to the end of a 512-token reply: TTFT (time to first token) + 512 ÷ decode speed. A coding agent pays this at every step. Lower is better. Pick a context size: one panel per metric, then the turn time across all sizes.
Tokens per second is not the whole story. At 128K, MTPLX decodes almost as fast as mlx-serve (70 vs 74 tokens/s), but its turn takes 15.1 s against 8.9 s: its TTFT on the next turn is 7.8 s and its prefill runs at 274 tokens/s against 759. Compare servers on turn time and cache behavior.
Splash: 99 tokens/s at 128K with the base model, 108 with Swift 1.5. mlx-serve: 74. ds4 stays at 43–54.
MTPLX drops to 274 tokens/s at 128K. The others stay almost flat.
In an agent session, every step sends the whole conversation again plus a small new part at the end. A server with a prefix cache keeps the already processed part and prefills only the new tokens. The wait is the tokens that miss the cache, divided by the prefill speed. No server prefilled faster than 832 tokens/s on this machine, so the scenario decides how many tokens miss. At 512K: 1K ≈ 1.5 s · 10K ≈ 15 s · 100K ≈ 2.5 min · 300K ≈ 7.5 min · 512K ≈ 13 min.
mlx-serve at 512K. The bar lengths are schematic; the times are measured.
| Case | Tokens prefilled again | Wait at 512K | When it happens |
|---|---|---|---|
| First message | 512K (100%) | 13 min | A session that already starts with 512K, or an empty cache. In daily use the context grows step by step, so this cost is paid in small parts, never at once. |
| History changes halfway | ~293K (56%) | 8 min | An edit of an earlier message, a compaction, a new system prompt or tool list, or a fork. The cost is the tokens after the point that changed. |
| Next turn | ~1K | 4.1 s | Every normal step: the tool result or the new message at the end. |
Splash is the exception. When the history changes halfway it reuses none of the prompt: 13 min at 512K with the base model, against 8 min on mlx-serve. Section 5 explains why.
All seven stacks hit the cache on the next turn. At 512K, ds4 hits 94.5% and prefills about 29K tokens again, so its next reply starts after 50 s. mlx-serve hits 99.8%, prefills about 1K tokens and starts after 4.1 s.
mlx-serve stays under 4 s up to 512K. ds4 grows from 6.4 s at 128K to 50 s at 512K.
At 512K the gap between 94.5% and 99.8% is about 28,000 tokens.
Share of the prompt the server took from the cache. First message is 0% by design. History changes halfway can reuse at most the part before the change; Splash reuses none. The two scenarios an agent repeats all day are user adds a message and next turn: above 90% is good.
The native context is 262,144 tokens. 512K uses YaRN 2.0, a context extension that oMLX does not support. 1M ran only on Splash. A cell shows the agent turn time, or why that size did not run.
No server used swap. mlx-serve locks 100–114 GB from 32K to 512K and Splash 108–117 GB from 32K to 1M, against 90–110 GB for oMLX, MTPLX and ds4 at 128K. Close other large apps before a long session.
Splash is Inco AI's inference engine on native Metal. It loads Flash-Next from a GGUF only: the base model as the unsloth UD-IQ4_XS, the Swift 1.5 fine-tune as the ukisai IQ4_XS. The tiles compare Swift 1.5 on Splash with the same fine-tune in MLX on mlx-serve 26.10.3, the stack I use every day. The gap belongs to the stack (runtime + weight format), not to the server alone.
Up to 128K the two quants tie on 26.10.3. Past 128K, Swift 1.5 is faster: 12.7 s against 14.5 s at 512K. The iQ pack lost decode speed from 26.10.1 to 26.10.3, while Swift 1.5 gained.
| Context | iQ-MLX 4.7 bpw · mlx-serve 26.10.1 | iQ-MLX 4.7 bpw · mlx-serve 26.10.3 | Swift 1.5 · mlx-serve 26.10.3 |
|---|---|---|---|
| 8K | 7.8 s84 tok/s | 7.9 s81 tok/s | 7.7 s84 tok/s |
| 32K | 8.2 s80 tok/s | 8.1 s82 tok/s | 8.0 s82 tok/s |
| 128K | 8.8 s74 tok/s | 8.9 s74 tok/s | 8.9 s74 tok/s |
| 256K | 9.8 s67 tok/s | 11.9 s57 tok/s | 9.2 s74 tok/s |
| 512K | 13.0 s56 tok/s | 14.5 s49 tok/s | 12.7 s57 tok/s |
3 runs per cell, except iQ on 26.10.1 at 256K and Swift 1.5 at 256K: 1 run. 512K uses YaRN 2.0 and the 4-bit KV cache on both builds.
Swift 1.5 is a community fine-tune that thinks less before it answers. On mlx-serve it scored the same as the base quant within the noise of these samples and reached the final answer 2.9× faster on GPQA and 2.0× faster on LiveCodeBench. Its agent turn time is the same, because prefill and the cache do not change.
Vendor sampling, reasoning effort xhigh, one run per model. Base: ddalcu iQ-MLX 4.7 bpw. Swift 1.5: Dankpaws/Swift1.5-Qwen3.8-Flash-Next-MLX-4.7bpw. The two packs also have different n-gram tables, so the comparison is between the packs, not only the fine-tune.
Conclusion
Splash had the shortest agent turn at every context size, from 8K to 1M, and it is the only server that served 1M. The cost is the cache: a change halfway in the history prefills the whole prompt again, 13 min at 512K against 8 min on mlx-serve. I did not check the quality of the base model on Splash. Among the MLX servers the runner-up is oMLX 0.7.0 (12.1 s at 128K), but it stops at 256K. With Swift 1.5, Splash is faster again (6.7 s at 512K, 9.3 s at 1M), and on mlx-serve 26.10.3 Swift 1.5 is the faster quant past 128K (same-build table).
These are the flags I measured. The data, the prompt generator and the scripts behind this page are in the repository.
Download unsloth/Qwen3.8-Flash-Next-GGUF
(UD-IQ4_XS, 94 GB) or ukisai/Swift-1.5-Qwen3.8-Flash-Next-GGUF
(IQ4_XS, 98 GB). This is the 1M setting; for 256K or 512K, set --max-context to 262144 or 524288.
Splash picks the DFlash2 draft model and the 8-bit KV cache by itself.
Splash 1.4.0, base model UD-IQ4_XS, 1M
splash serve --model unsloth/Qwen3.8-Flash-Next-GGUF:UD-IQ4_XS \
--host 0.0.0.0 --port 8585 --max-context 1000000 \
--revision 766911a6b7369840a91dbcd95f9f997acaab6cd6 \
--idle-release off --language-only --no-webui --offline \
--verify-rows auto
Splash 1.4.0, Swift 1.5 IQ4_XS, 1M
splash serve --model ukisai/Swift-1.5-Qwen3.8-Flash-Next-GGUF:IQ4_XS \
--host 0.0.0.0 --port 8585 --max-context 1000000 \
--revision 0142554c963a8653912c0c8283f05f13f63653f3 \
--idle-release off --language-only --no-webui --offline \
--verify-rows auto
Download ddalcu/Qwen3.8-Flash-Next-MLX-Serve-iQ-MLX-4.7bpw (107 GB) and mlx-serve 26.10.3, which exposes OpenAI and Anthropic compatible endpoints. The prefix cache flags matter: with the default 2 GB cache, a 128K session read the whole prompt again on every turn. For 512K, use the 4-bit KV cache; with 8-bit, some long prompts did not fit in memory.
Up to 256K (native context)
mlx-serve --model ~/models/Qwen3.8-Flash-Next-MLX-Serve-iQ-MLX-4.7bpw \
--serve --host 127.0.0.1 --port 11234 \
--ctx-size 262144 --mtp --ssm-checkpoint-max 16 \
--prefix-cache-mem 16GB --prefix-cache-disk 100GB --prefix-cache-entries 64
512K (YaRN 2.0 + 4-bit KV cache)
mlx-serve --model ~/models/Qwen3.8-Flash-Next-MLX-Serve-iQ-MLX-4.7bpw \
--serve --host 127.0.0.1 --port 11234 \
--ctx-size 524288 --mtp --ssm-checkpoint-max 16 \
--prefix-cache-mem 16GB --prefix-cache-disk 100GB --prefix-cache-entries 64 \
--kv-quant 4 --kv-attn-mode fused \
--config-overrides '{"text_config":{"rope_parameters":{"rope_type":"yarn","factor":2.0,"original_max_position_embeddings":262144},"max_position_embeddings":524288}}'
Does a server or quant break the model? Not in these runs: the five stacks I checked are within a few cases of each other. One run per cell, on different dates, with a small sample. Read it as a sanity check, not as a ranking. ds4 and Splash with the base model were not checked.
Context sizes differ: the three base-model stacks ran at 128K, the two Swift 1.5 stacks at 262K (the 262K columns of the table below). HumanEval with the prompt's import lines added before the answer; on Splash it ran twice at 262K (158 and 159 of 164) and the bar shows the first run. LiveCodeBench v6: 50 questions (seed 42), graded with the official import lines. Instruction following: 20 prompts with format constraints, an IFEval-style probe. Tool calls A = jdhodges tool-call test; tool calls B = Veerman tool-call test. mlx-serve with the iQ pack: 2026-10-11 run on 26.10.1; oMLX and MTPLX (with --memory-limit max): 2026-10-09 runs, without instruction following. The oMLX LiveCodeBench bar comes from a 2026-10-15 run of the same pack on oMLX 0.7.1.dev1; MTPLX was not measured. Swift 1.5 stacks: 2026-10-25 runs.
| Test | Swift 1.5 · mlx-serve · 262K | Splash · 262K | Splash · 512K | Splash · 1M |
|---|---|---|---|---|
| HumanEval (164) | 158/164 | 158/164 · 159/164 | 156/164 | 155/164 · 158/164 |
| GPQA-Diamond (50) | 43/50 | 41/50 | 43/50 | 43/50 |
| LiveCodeBench v6 (50) | 47/50 | 47/50 | 47/50 | 47/50 |
| Instruction following (20) | 19/20 | 19/20 | 18/20 | 19/20 |
| Tool calls A (40) | 34/40 | 37/40 | 37/40 | 36/40 |
| Tool calls B (12) | 10/12 | 10/12 | 10/12 | 9/12 |
| Long-context recall at the server's size (8) | 8/8 | 8/8 | 8/8 | 8/8 |
One run per cell, vendor sampling, reasoning effort xhigh; each column starts the server at that context size. HumanEval with the prompt's import lines, as in the chart; it ran twice at 262K and 1M on Splash, and the 1M result is within the run-to-run noise. Long-context recall: 8 questions about a document filled to the server's size.
bench/engine-updates-2026-10, bench/swift15-flashnext-2026-10,
bench/stack-updates-2026-10 and bench/splash-longctx-2026-10).--memory-limit max. Short requests without history skip its session cache, so the test
sends a 64-token warm-up first.frequency_penalty 0, as with mlx-serve 26.10.3: with 1, the tool-call test failed on both servers.PrefillDoesNotFit: they need about 18 GB for the
prefill, and 7 to 9 GB are free. 2 of 5 requests failed with Swift 1.5 and 3 of 5 with the iQ pack, so the page has no
1M turn time for mlx-serve.One row per server and context size. Times in seconds (TTFT = time to first token). Decode and prefill in tokens/s, memory in GB.