inference/research
verifiedhigh · 0.91updated 2026-10-05

NVIDIA Dynamo

cuda, rocm

Fields

id
engines/nvidia-dynamo
Repo
ai-dynamo/dynamo
Languages
RustPythonGo
License
Apache-2.0 (README badge and SPDX headers; GitHub's license API reports NOASSERTION because some bundled paths ship NVIDIA-proprietary components, e.g. NIXL's ucx IB modules)
First release
2025
Design goal
throughput-firstlow-latencymulti-modeldatacenter-scale orchestrationSLA-based autoscaling
Scheduling
continuous-batchingpaged-kvprefix-cachechunked-prefilldisaggregated-prefill-decodeKV-aware-routingSLA-based-planner
Backends
cudarocm
Formats
safetensors
Notable features
Orchestration layer ABOVE the inference engines - the README is explicit that it 'doesn't replace SGLang, TensorRT-LLM, or vLLM, it turns them into a coordinated multi-node inference system'; backend support matrix lists all three for disaggregated servingDisaggregated serving with independently scalable prefill and decode poolsKV-aware routing to avoid redundant prefill computation across replicasSLA-based Planner for autoscaling against measured latency, and a profiler that derives cost models for disaggregated deployments (per-engine disagg templates for vLLM, SGLang, TRT-LLM)KVBM block manager for GPU/host KV tiering - marked complete for TensorRT-LLM and vLLM, in progress for SGLangKV transfer via NIXL (NixlConnector), Mooncake and LMCache connectorsRust core with Python extensibility; frontend/worker split with graph-deployment CRDs for Kubernetes
Hardware caveats
NVIDIA-originated: the disaggregation and NIXL paths are built on CUDA/UCX, so the CUDA support is first-class and anything else is secondaryNIXL itself is Linux-only - 'macOS and Windows are not currently supported; use a Linux host or container/VM' - so the whole KV-transfer stack is Linux-onlyNIXL was tested with UCX 1.23.x and needs GDRCopy for maximum RDMA performance (works without it, slower)Multi-node disaggregated deployments require an RDMA-capable fabric; the known-failure cases in the tracker are all fabric-configuration failures rather than code failures
Best for
Multi-node production serving where prefill and decode need to be scaled and costed independentlyKubernetes-based deployments that want an OpenAI-compatible frontend, SLA-driven autoscaling and KV-aware routing as one stackFleets that already run vLLM, SGLang or TensorRT-LLM and want disaggregation without changing engine
Avoid for
Single-node or single-GPU serving, where the README itself says 'If you're running a single model on a single GPU, your inference engine alone is probably sufficient'Non-Linux hosts - the NIXL dependency alone rules out Windows and macOSWorkloads that need bit-reproducible output across prefill and decode pools without extra configuration; the KV compatibility hash omits batch-invariance mode and some connectors have no model-level check at all
Tracing support
per-request
Verified negatives
no
notes
KV transfer path: NIXL as the primary connector (NixlConnector), with UCX as the default transport and RDMA/GPUDirect for inter-node, plus Mooncake and LMCache as alternative connectors and KVBM for GPU/host tiering. UCX-specific env vars are required - the vLLM connector guide notes NCCL variables such as NCCL_IB_HCA do not apply to the NIXL path. Does Dynamo supersede or complement the Triton/TRT-LLM paths? Complement, and by design it does not try to replace them: it is an orchestration layer that drives them. The TRT-LLM maintainer response on issue #17665 is the clearest statement of the relationship - 'TensorRT-LLM disaggregated serving is now planned to fully adopt the Python transceiver', i.e. Dynamo supplies the runtime and TRT-LLM supplies the transceiver implementation. Handoff contract as implemented (components/src/dynamo/common/backend/disagg.py): prefill workers have max_tokens clamped to 1 because 'producing more than one token is wasted compute and breaks the prefill->decode handoff contract', and a decode-mode worker raises if the request arrives without a prefill_result, so a missing handoff is a hard error rather than a silent recompute. Its tracker also shows the operational surface is still young: open multi-node hang reports (#11914), a UCX_NET_DEVICES silent-garbage root cause (#12463, triaged urgent), an LMCache-on-vLLM silent cache corruption report (#14416), and an RFC to bind batch-invariance into KV namespaces (#58263 in vLLM). ||| MAINTENANCE (dated fact, GitHub API, 2026-10-04): last commit 2026-10-04 (0 months), latest release v1.5.0 published 2026-09-21, 420 contributors, open_issues_count 1658 (issues PLUS pull requests), NOT archived, 8219 stars. Actively developed with a large team. DEPLOYMENT: NO EVIDENCE OF PRODUCTION DEPLOYMENT FOUND as of 2026-10-04 - see [[ev-production-evidence-is-scarce-and-nearly-always-single-site]]. Note that this is a weaker negative than for a small library: the README publishes an offline batch-inference throughput TUNING GUIDE with a worked example (a log line showing 'Decode batch. #running-req: 233, #token: 370959, token usage: 0.82, cuda graph: True, gen throughput (token/s): 4594.01, #queue-req: 317'), which is evidence that operators tune this engine seriously but is explicitly a configuration guide, not a report of anyone's deployment. FEATURE AXES: all seven UNSTATED as of 2026-10-04; nothing was confirmed from its public materials in this pass. Given that this engine exists to compose vLLM and SGLang with disaggregated serving, disaggregated P/D is the axis most likely to be YES and most worth checking first - but it is recorded as unstated, not assumed. TRACING VERIFIED 2026-10-05, read at main 2026-10-05. lib/backend-common/src/telemetry.rs is explicit about the convention in its own module doc: use tracing::info_span! for static span names, which nest under the framework's engine.generate parent via the runtime's .instrument chain, and start_span() for runtime-computed names, which goes through OTel directly 'while still inheriting the bridged parent context'. start_span returns a NO-OP SpanGuard when no valid parent span context exists, so instrumentation never panics and never emits an orphan root span - there is a test asserting exactly that (start_span_is_noop_without_bridge). Both paths land in one OTel tree. The frontend collector also records ttft_ms onto the request span, so a trace shows the latency that the dynamo_frontend_time_to_first_token_seconds histogram aggregates. per-request rather than per-phase: one span per generate call with TTFT as an attribute. The metrics story is the bigger story and is recorded in the metric_exposure set: Dynamo BRIDGES vendor engine registries (vllm:, sglang:, trtllm_, lmcache:) into one /metrics rather than reimplementing them, so a Dynamo endpoint serves metrics that belong to those engines' records, plus its own generated dynamo_* names.

Notes

KV transfer path: NIXL as the primary connector (NixlConnector), with UCX as the default transport and RDMA/GPUDirect for inter-node, plus Mooncake and LMCache as alternative connectors and KVBM for GPU/host tiering. UCX-specific env vars are required - the vLLM connector guide notes NCCL variables such as NCCL_IB_HCA do not apply to the NIXL path. Does Dynamo supersede or complement the Triton/TRT-LLM paths? Complement, and by design it does not try to replace them: it is an orchestration layer that drives them. The TRT-LLM maintainer response on issue #17665 is the clearest statement of the relationship - 'TensorRT-LLM disaggregated serving is now planned to fully adopt the Python transceiver', i.e. Dynamo supplies the runtime and TRT-LLM supplies the transceiver implementation. Handoff contract as implemented (components/src/dynamo/common/backend/disagg.py): prefill workers have max_tokens clamped to 1 because 'producing more than one token is wasted compute and breaks the prefill->decode handoff contract', and a decode-mode worker raises if the request arrives without a prefill_result, so a missing handoff is a hard error rather than a silent recompute. Its tracker also shows the operational surface is still young: open multi-node hang reports (#11914), a UCX_NET_DEVICES silent-garbage root cause (#12463, triaged urgent), an LMCache-on-vLLM silent cache corruption report (#14416), and an RFC to bind batch-invariance into KV namespaces (#58263 in vLLM). ||| MAINTENANCE (dated fact, GitHub API, 2026-10-04): last commit 2026-10-04 (0 months), latest release v1.5.0 published 2026-09-21, 420 contributors, open_issues_count 1658 (issues PLUS pull requests), NOT archived, 8219 stars. Actively developed with a large team. DEPLOYMENT: NO EVIDENCE OF PRODUCTION DEPLOYMENT FOUND as of 2026-10-04 - see [[ev-production-evidence-is-scarce-and-nearly-always-single-site]]. Note that this is a weaker negative than for a small library: the README publishes an offline batch-inference throughput TUNING GUIDE with a worked example (a log line showing 'Decode batch. #running-req: 233, #token: 370959, token usage: 0.82, cuda graph: True, gen throughput (token/s): 4594.01, #queue-req: 317'), which is evidence that operators tune this engine seriously but is explicitly a configuration guide, not a report of anyone's deployment. FEATURE AXES: all seven UNSTATED as of 2026-10-04; nothing was confirmed from its public materials in this pass. Given that this engine exists to compose vLLM and SGLang with disaggregated serving, disaggregated P/D is the axis most likely to be YES and most worth checking first - but it is recorded as unstated, not assumed. TRACING VERIFIED 2026-10-05, read at main 2026-10-05. lib/backend-common/src/telemetry.rs is explicit about the convention in its own module doc: use tracing::info_span! for static span names, which nest under the framework's engine.generate parent via the runtime's .instrument chain, and start_span() for runtime-computed names, which goes through OTel directly 'while still inheriting the bridged parent context'. start_span returns a NO-OP SpanGuard when no valid parent span context exists, so instrumentation never panics and never emits an orphan root span - there is a test asserting exactly that (start_span_is_noop_without_bridge). Both paths land in one OTel tree. The frontend collector also records ttft_ms onto the request span, so a trace shows the latency that the dynamo_frontend_time_to_first_token_seconds histogram aggregates. per-request rather than per-phase: one span per generate call with TTFT as an attribute. The metrics story is the bigger story and is recorded in the metric_exposure set: Dynamo BRIDGES vendor engine registries (vllm:, sglang:, trtllm_, lmcache:) into one /metrics rather than reimplementing them, so a Dynamo endpoint serves metrics that belong to those engines' records, plus its own generated dynamo_* names.

Cross-references

This record references no other records — it is a leaf. It is cited by 16.