Disaggregated serving: prefill and decode in specialised pods
Contents
TL;DR
LLM inference has two phases with opposite profiles: prefill (processing the whole prompt in one go) is compute-bound, decode (generating token by token) is memory-bandwidth-bound. Running them on the same GPU forces a choice between two incompatible optimal hardware profiles, and leaves between 60 % and 80 % of peak capacity unused. The industry consolidated the pattern in 2026: disaggregated serving, separate pods for each phase, connected by a KV cache transfer channel (NIXL over UCX, RDMA, or NCCL as a fallback). DistServe demonstrated 7.4× more request rate at the same SLO; NVIDIA Dynamo 1.0 (GA at GTC 2026) takes the pattern to production at datacenter scale. Mixing heterogeneous hardware, H100 for prefill and commodity GPUs for decode, cuts up to 48 % off the cost per token. This article explains the why, the how, and the numbers that matter for a typical on-premise infrastructure.
You are here: Deploy
Disaggregated serving is an architectural decision in the Deploy stage of the six-stage LLMOps pipeline. It does not change the model, it does not change the data, it does not change the evals. It only changes how inference pods are spread over the GPU hardware. But that change moves aggregate throughput between 2× and 7×.
The analogy: the kitchen with two brigades
A serious industrial kitchen, any kitchen serving more than 50 covers a night, runs with two distinct brigades and two physically separate spaces.
The prep brigade starts at dawn. Its job is the mise en place: chopping, marinating, blanching, boiling stocks, preparing complex components. Equipment: good knives, big burners, convection ovens, 40-litre pots. It is capacity-intensive work and it is done in one batch. When it finishes, everything is left in labelled trays ready to use.
The service brigade comes in mid-afternoon. Its job is service: taking the trays from prep, heating portions, plating, running the pass. Equipment: salamanders, small griddles, thin spatulas, plenty of crockery. It is wrist work, rhythm work, not-failing-the-customer-who-has-the-plate-in-front-of-them work. Capacity per hour matters less than latency per plate.
If you make the same person do prep and service, both suffer. The cook is idle while doing mise en place in the middle of the afternoon. They have to stop and plate up when five orders land at once. Their working kit is designed for one or the other, not for both.
Serious kitchens solved this decades ago: separate brigades, separate spaces, separate equipment. The only thing that crosses between them is the trays of mise en place.
The trays are the KV cache. The separation is disaggregated serving. The handover from prep to service is the KV cache transfer, solved today with NIXL over RDMA. And the specialised pods are the two brigades with their optimal kit.
Quick recap: prefill and decode
A request to an LLM always goes through two phases:
Prefill. Take the complete prompt (say, 4,000 tokens) and process it in a single pass through all the layers of the model. The result is the KV cache of those 4,000 tokens (see the previous article on KV cache if you want to recall exactly what it holds). This step is massively parallel: all the tokens go through the attention matrices at once, which translates into huge, dense matrix multiplications. The GPU sits at 90-95 % compute utilisation. TTFT (time to first token) is determined by this phase.
Decode. Once the KV cache is ready, the model generates tokens one by one. Each new token is a pass through all the layers with a single query vector, reading the whole accumulated KV cache to compute attention. There is no parallelism between tokens (each one depends on the previous). What limits you here is not compute but bandwidth: every step has to read the model’s full weights from HBM. The GPU sits at 20-40 % compute utilisation, but at 90 % HBM utilisation. TBT (time between tokens) is determined by this phase.
| Phase | Characteristic | Bottleneck | Key metric |
|---|---|---|---|
| Prefill | Massive parallel compute over N tokens at once | TFLOPS (compute) | TTFT |
| Decode | Streaming weights from HBM, 1 token at a time | HBM bandwidth | TBT (inter-token latency) |
The asymmetry is structural: prefill burns compute and leaves memory half idle, decode does the opposite. A GPU designed to be excellent at both at once is a GPU designed to be badly used all the time.
Why putting them on the same GPU is a bad deal
Until 2023, the universal assumption was to run prefill and decode in the same inference process, on the same GPU. The engine scheduler (vLLM, TGI, Triton) decided on each cycle whether to prefill a new request or decode the ones already in flight. The intuition was that sharing hardware saves money.
The intuition is wrong. The problem has three faces:
Latency interference. When the engine decides to prefill a new request, it interrupts every decode in progress. That pushes up the TBT of the other requests. The user who was watching tokens flow smoothly down the screen notices a stall of several hundred milliseconds. This is known as prefill-decode interference and it degrades the experience visibly as concurrency rises.
Sub-optimal hardware for each phase. An H100 SXM has 989 TFLOPS BF16 of compute and 3.35 TB/s of HBM3. It is excellent for prefill, where compute is the limit. For decode, where the only thing that matters is bandwidth, those 989 TFLOPS are 60-70 % wasted. Conversely, a GPU with less compute but similar relative bandwidth (RTX 4090, L40S) would handle decode just as well for a fraction of the price.
Low aggregate utilisation. In real workloads with Llama 3 70B and 512-token outputs, around 80 % of the wall-clock is spent in decode. That means 80 % of your H100 cluster budget is doing memory reads, not calculations. It is like paying for a Ferrari to use it in a car park queue.
The idea: specialised pods, KV cache as the deliverable
Disaggregated serving breaks the inference cycle into two distinct services:
Prefill pod. Receives the prompt, runs the prefill, produces the KV cache. Hardware: high-compute GPUs (H100, H200, B200). Optimised for aggressive batching and throughput, not for individual latency: if 32 prompts arrive within 100 ms, it processes them together.
Decode pod. Receives the already-built KV cache, runs the token-by-token generation, streams to the client. Hardware: GPUs with good bandwidth but ideally cheaper per TFLOPS (RTX 4090, L40S, A100, even A30 depending on the case). Optimised for per-token latency (low TBT).
Between the two: a KV cache transfer over the network, which can be node-local (shared memory, NVLink), intra-rack (RDMA with InfiniBand or RoCE) or cross-rack (NIXL over UCX). The cost of this transfer scales linearly with context length, and it is the economic crux of the scheme.
The transfer protocol: the economics of movement
The KV cache transferred for a Llama 3 70B with 4K of context weighs roughly 2.6 GB (80 layers × 8 KV heads × 128 dim × 4,096 tokens × 2 (K and V) × 2 bytes in BF16). Moving 2.6 GB between two GPUs is not trivial:
| Channel | Effective bandwidth | Time for 2.6 GB |
|---|---|---|
| Intra-node NVLink (NVSwitch) | ~450 GB/s | ~6 ms |
| Shared memory (same node, PCIe 5) | ~60 GB/s | ~45 ms |
| RDMA InfiniBand 400 Gbps | ~50 GB/s | ~55 ms |
| RDMA RoCE 200 Gbps | ~25 GB/s | ~105 ms |
| TCP/IP 10 GbE | ~1 GB/s | ~2.6 s |
The immediate reading: above InfiniBand grade, the transfer is comfortable. Below it, it ruins the very TTFT we are trying to improve. Disaggregated serving is only viable with a decent interconnect. It is not a pattern for clusters built out of consumer Ethernet switches.
NVIDIA answered this with NIXL (NVIDIA Inference Transfer Library), released in mid-2025: a library that abstracts the transport (UCX, NCCL, direct RDMA verbs, shared memory) and picks the best available path automatically. vLLM has integrated it since late 2025 through the NixlConnector. It is now the de facto default for new deployments.
Real implementations in May 2026
The pattern’s path over two years:
2024 Jan · DistServe (HKU + UCSD): 7.4× requests at the same SLO
2024 May · SplitWise (Microsoft): variant with heterogeneous hardware
2024 Dec · experimental vLLM disagg (SharedStorage + PyNcclConnector)
2025 Mar · NIXL release (NVIDIA): unified transfer library
2025 Jul · stable vLLM NixlConnector
2025 Nov · SGLang, llm-d, MoonCake adopt the pattern
2026 Mar · NVIDIA Dynamo 1.0 GA (GTC 2026): production-ready at datacenter scale
As of today, the pattern is the default in any serious serving framework. The ones still monolithic are the small ones or the educational ones.
Three realistic options for an on-premise infrastructure:
- vLLM disagg with NixlConnector. The most open route, requiring two sets of vLLM pods to be deployed (one with
--kv-transfer-config '{"kv_role":"producer"}', another with"kv_role":"consumer") plus a proxy router. Enough for clusters of 4-16 GPUs. - SGLang with disagg. Conceptually equivalent, better performance on some MoE workloads.
- NVIDIA Dynamo 1.0. The one taking over at datacenter scale. It covers routing, KV cache management, monitoring and scheduling in a single control plane. Heavier, but the reference solution if your cluster grows beyond 32 GPUs.
The numbers that matter
What disaggregation unlocks, in direct terms:
| Metric | Aggregated (monolithic) | Disaggregated | Improvement |
|---|---|---|---|
| Goodput (req/s at the SLO) | baseline | 1.4 – 2× | up to 2× |
| TTFT under high load | rises sharply from QPS 4 | stable up to QPS 7+ | ~2× |
| Request rate at the same SLO (DistServe paper) | baseline | 7.4× | 7.4× |
| MoE throughput on Blackwell (Dynamo, GB300 NVL72) | baseline (Hopper) | up to 50× | depends on the model |
| Cost per token (heterogeneous H100 + commodity) | baseline (all H100) | -48 % | almost half |
These numbers have to be read carefully: the most spectacular ones (7× and 50×) need specific hardware (Blackwell GB200/GB300 NVL72) and specific models (large MoE). The realistic range for a typical on-premise setup is 1.4-2× in goodput and -30 to -50 % in cost per token, depending on how heterogeneous the GPU mix is and how optimised the KV cache transfer is.
Heterogeneity: the radical version
The logical next step, proposed by SplitWise in 2024 and matured in 2025-2026 (Cronus, Tessera and others), is to mix GPU types: expensive high-compute GPUs for prefill, commodity GPUs with good bandwidth for decode.
Indicative cost (typical market prices in mid-2026):
- H100 SXM: ~30-40 kUSD capex, ~3-4 USD/h amortised. Compute-heavy profile.
- L40S: ~8-10 kUSD capex, ~1.5 USD/h. Intermediate profile, 864 GB/s of bandwidth.
- RTX 4090: ~1.5 kUSD capex, ~0.30 USD/h. Modest compute profile but 1 TB/s of GDDR6X bandwidth, enough for decode of models up to ~30B parameters.
A realistic mixed cluster for serving an 8B model:
2× RTX 4090 (prefill batch) → ~3,000 USD capex, ~0.60 USD/h
4× RTX 4090 (decode pool) → ~6,000 USD capex, ~1.20 USD/h
TOTAL → ~9,000 USD capex, ~1.80 USD/h
Against the monolithic alternative with equivalent throughput:
2× H100 SXM (all in one) → ~70,000 USD capex, ~7 USD/h
The same throughput at a fraction of the capex and a quarter of the hourly cost, at the price of operational complexity: you now have two pools to coordinate, a transfer network to look after, and a scheduler that is not trivial.
For larger models (Llama 3 70B), the decode pool no longer fits on a single 4090 (the model does not fit in 24 GB, not even quantised to INT4 with headroom). There the sensible mix is H100 for prefill plus L40S or A100 80GB for decode, with a typical saving of 30-40 % over the all-H100 option.
Applied to typical on-premise hardware
Case 1 — One or two RTX 4090s: monolithic still wins
With a single GPU there is no disaggregation to speak of: the pattern needs at least two GPUs in separate pods. With two 4090s you can technically try it (one for prefill, one for decode with the KV cache transferred over PCIe 5 or basic RDMA), but the transfer overhead eats the gain for small models where prefill is already fast.
Recommendation: stay monolithic (traditional vLLM, properly configured with a quantised KV cache). The next justifiable level of complexity is a cluster with a fast interconnect.
Case 2 — 4×H100 SXM cluster (320 GB, NVLink): the sweet spot
The minimum realistic configuration for serious disaggregation, serving a 70B model in production:
2× H100 (TP=2) → 2 prefill pods
2× H100 (TP=2) → decode pods with several instances sharing TP
NIXL over NVLink → KV cache transfer <6 ms
Router (vLLM or Dynamo) → prompt distribution and streaming
Realistic expected result: goodput 1.6-1.9× relative to the same cluster running monolithic, with TTFT stable up to loads of QPS 7-8 (against the QPS 4 at which the monolithic setup starts to degrade).
If the heterogeneous mix is possible (adding 4-8 L40S to the cluster to make the decode pool), the cost per token drops a further 25 % to 35 %, while still serving the 70B model whole.
Position within the architecture
Disaggregated serving is a cross-cutting layer over almost everything discussed in previous articles. It touches:
- The KV cache because it is the artefact transferred between pods. Without a solid grasp of how much the cache weighs and how it grows with context, you cannot size the transfer.
- Continuous fine-tuning because multi-LoRA hot-swap keeps its semantics: each pod (prefill or decode) loads the adapters separately, and the router decides which adapter to apply in each phase.
- Cluster topology: it changes the recommended HW, the networking required and the cost model.
If you are designing an inference infrastructure for 2026 from scratch, disaggregation stops being optional for any cluster beyond 4 GPUs of capacity. If you are modernising an existing one, it is the upgrade with the best return per euro invested, provided the networking between pods is decent (intra-node NVLink or intra-rack RDMA as a minimum).
What we have not covered (upcoming articles)
- NIXL in detail: how it picks the optimal transport, how UCX is configured, what happens when RDMA fails and you have to fall back to TCP.
- Routing scheduler: how the orchestrator decides which pod gets which request, dynamic batching, priority handling.
- Multi-tenant disagg: KV cache isolation between tenants, per-adapter ACLs, multi-LoRA over specialised pods.
- Disagg + prefix caching: how it combines with the KV cache reuse pattern when several prompts share a prefix (a common system prompt).
- Disagg at the edge / local inference: viability on home hardware (4090 + Mac Studio, for example), where the transfer depends on Thunderbolt or residential Ethernet.
See also
- The six-stage LLMOps pipeline — the master map the Deploy stage belongs to. This post digs into one concrete architectural decision within that stage.
- The GPU cluster as a multi-tenant platform — the Gateway/Quota/Isolation/Observability layered pattern on top of which the disaggregation described here sits: the H100 cluster serving several tenants combines both patterns.
- LLM inference operators on Kubernetes — the operators (vLLM Production Stack, NVIDIA Dynamo, llm-d, OME) that materialise the specialised prefill and decode pods in Kubernetes.
- KV cache: the working memory that holds up LLM inference — the exact artefact transferred between pods, with the full formula for its size.
- PagedAttention from the inside: blocks, page table, eviction and the state of the art of KV cache in 2026 — the KV cache mechanics that disaggregation exploits at block level, and the landscape of derived optimisations (vAttention, LMCache, RadixAttention).
- Continuous fine-tuning in production — how multi-LoRA hot-swap coexists with disaggregation: each pod loads adapters separately, the router chooses.
- Quantization for LLM inference: FP8, INT4 and GGUF — the two pools (prefill and decode) can be quantised asymmetrically: prefill keeps more precision, decode prioritises throughput. The maths and the formats are there.
- Speculative decoding: the secretary who anticipates what the boss is going to say — speculative only helps in the decode phase (it does not touch prefill); disaggregation makes it easier by isolating the decode pool where the technique can be applied without contaminating the prefill one.
- FlashAttention v1/v2/v3/v4: the librarian who never clears the desk — the kernel each pod uses underneath. Prefill (compute-bound) and decode (memory-bound) benefit from FA3/FA4 in different ways and allow a backend to be chosen per phase.
- MoE inference: the call centre with 256 specialists — the real DeepSeek-V3 deployment combines EP=32 in prefill (4 nodes) with EP=144 in decode (18 nodes): disaggregation is the prerequisite that allows expert parallelism to be specialised per phase.
- Multi-LoRA serving: the single translator with a thousand glossaries — once pods are separated, adapters are managed per pool; the 2026 strategy is to replicate hot ones on every pod (prefill and decode) and evict cold ones.
- Continuous batching — the layer underneath. DistServe is the paper that contributed the goodput metric and the idea of disaggregating prefill/decode; understanding the iterative scheduler is a prerequisite to understanding why the separation unlocked additional gains.
- Capacity planning for on-premise LLM inference — disaggregation appears as the third sizing lever when the workload’s prefill/decode mix is asymmetric; when to apply it and how much it saves are quantified there.
- NVLink, NVSwitch and NCCL: the cable every token travels down — moving the KV cache between the prefill pool and the decode pool travels over the same interconnect as the all-reduces and competes with them; designing the disaggregation without counting that transfer cost is the classic trap.
- The kitchen door the maître never looked at: network NUMA, Cilium eBPF and DRANET — when that KV cache crosses by RDMA across nodes, a badly placed NIC pays for it in latency; the fourth leg (NIC↔GPU locality via DRANET) is what keeps separating prefill and decode from being expensive in transfer.
- From disk to HBM: cold start and model loading — bringing up decode pools on demand pays the cold start of loading the model into every new pod; the elasticity of the pattern depends on how fast they start.
- SM, CUDA streams and CUDA graphs — pure decode pods are the ideal case for
FULL_DECODE_ONLY: they maximise the benefit of the CUDA graph in the most launch-bound phase.
References
- Zhong et al., DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving (OSDI 2024).
- Patel et al., SplitWise: Efficient Generative LLM Inference Using Phase Splitting (ISCA 2024).
- NVIDIA, NVIDIA Dynamo 1.0: Production-Ready Disaggregated Inference (GTC 2026, March): https://developer.nvidia.com/blog/nvidia-dynamo-1-production-ready/.
- NVIDIA, NIXL: NVIDIA Inference Transfer Library — official documentation.
- vLLM, Disaggregated Prefilling: https://docs.vllm.ai/en/stable/features/disagg_prefill/.
- vLLM, NixlConnector Usage Guide: https://docs.vllm.ai/en/stable/features/nixl_connector_usage/.
- Hao AI Lab, Disaggregated Inference: 18 Months Later (UCSD, 2025) — technical retrospective on the DistServe paper.