What vLLM is today
Code version: vLLM @ 3e44c0d · 2026-10-22
In one sentence
vLLM is an engine that runs LLMs and serves them over HTTP; one engine core, V1, sits behind both of its entry points.
The idea#
What vLLM is#
vLLM calls itself "a fast and easy-to-use library for LLM inference and serving" (README.md:24). The package description says "a high-throughput and memory-efficient inference and serving engine for LLMs" (pyproject.toml:22). An inference engine runs a trained model and makes its tokens. It adds batching, a KV cache and a scheduler around the model (What an LLM does). A serving engine also accepts requests from many users over the network and streams the answers back.
This site explains vLLM as a serving engine. The main path is the command vllm serve. It starts an OpenAI-compatible server: "Launch a local OpenAI-compatible API server to serve LLM completions via HTTP" (vllm/entrypoints/cli/serve.py:39-40). Any client that can talk to the OpenAI API can then talk to your model.
One engine: V1#
vLLM has exactly one engine at this commit: the V1 engine in vllm/v1/. The older V0 engine is gone. Only two old names remain, and both are aliases of V1 classes:
vllm.engine.async_llm_engine.AsyncLLMEngine = AsyncLLM(vllm/engine/async_llm_engine.py:4-6).vllm.engine.llm_engine.LLMEngine = V1LLMEngine(vllm/engine/llm_engine.py:4-6).
So when you read "AsyncLLMEngine" in old examples, it is the V1 AsyncLLM. This site uses only the V1 names.
Two ways to use it#
- Online serving with
vllm serve(this site). An HTTP client sends a request, for examplePOST /v1/chat/completions. The API server turns it into an engine request and streams the tokens back. The page The OpenAI-compatible API explains the API. - Offline inference with the
LLMclass (a side note). Your Python script makesLLM(model=...)and callsgenerate()orchat(). There is no HTTP server. The class builds a V1LLMEngine(vllm/entrypoints/llm.py:341-343). Its own docstring says that it "is intended to be used for offline inference" (vllm/entrypoints/llm.py:171-173).
What runs where#
One vllm serve deployment is a group of processes. Each one has its own job:
- The front end (the API server process) runs the HTTP routes, the chat template, the tokenizer and
AsyncLLM. - The EngineCore process runs the scheduler and the KV cache manager in a loop. It tells the workers what to compute in each engine step.
- The workers own the GPUs and run the model. With one GPU, the worker is an object inside the engine core process.
The page The process and thread architecture of vllm serve explains this split in full. The page Processes, ZMQ and shared memory explains how the processes talk to each other.
An everyday comparison#
Think of a restaurant. The waiter (the front end) takes orders from many tables and brings the dishes back. The head chef (the engine core) decides which dishes to cook in the next round. The cooks at the stoves (the workers) do the cooking. A take-away counter (the LLM class) uses the same kitchen, but without waiters.
The comparison stops here: a real kitchen cooks each dish once. Without speculative decoding, vLLM makes at most one new token per request in each step, and repeats the step until each answer is complete.
The picture#
Read panel 1 from left to right: this is the path of every request on this site. Panel 2 shows the offline path. It shares the engine core, but the front end is your own script. The blue, amber and violet colours mark the online front end, the offline path and the shared engine core.
In vLLM#
This is a basics page, so this part gives only pointers. The tour Tour: Life of a chat request follows one request through all of the code.
- The command. The package installs one console script,
vllm, that callsvllm.entrypoints.cli.main:main(pyproject.toml:42-43). With one API server,vllm serveruns the server in the same process as the command (vllm/entrypoints/cli/serve.py:154-156). - The front end. The API server makes an
AsyncLLM(vllm/entrypoints/launchers/api_server/entry.py:94-99).AsyncLLMalways starts the engine core in a separate process, throughmake_async_mp_client(vllm/v1/engine/async_llm.py:193-201). The page The engine client: AsyncLLM in the API server explains it. - The engine core.
EngineCoreProcinvllm/v1/engine/core.pyruns the busy loop. The page The engine core loop: threads, queues and the busy loop explains it.
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from vllm.v1.engine.async_llm import AsyncLLM
AsyncLLMEngine = AsyncLLM # type: ignore
"""The `AsyncLLMEngine` class is an alias of [vllm.v1.engine.async_llm.AsyncLLM][]."""AsyncLLM.Deep dive#
The sections below give the full detail. Open them one at a time, or use Open all deep dives at the top of the page.
Deep diveThe offline LLM class: how it reaches the engine core
The LLM class is a side path on this site. It differs from vllm serve in three ways:
- It uses the synchronous V1
LLMEngine, notAsyncLLM(vllm/entrypoints/llm.py:341-343). LLMEngineturns on multiprocess mode whenVLLM_ENABLE_V1_MULTIPROCESSINGis true (vllm/v1/engine/llm_engine.py:186-188). The default is"1"(vllm/envs.py:1442-1444). Then the client is aSyncMPClientwith ZMQ and an engine core process. WithVLLM_ENABLE_V1_MULTIPROCESSING=0, the client is anInprocClient, and the engine core runs in your process (vllm/v1/engine/core_client.py:128-136).- It has statistics off by default (
vllm/entrypoints/llm.py:225-226).
AsyncLLM does not read VLLM_ENABLE_V1_MULTIPROCESSING. It always calls make_async_mp_client (vllm/v1/engine/async_llm.py:193), and an asyncio client without multiprocessing raises NotImplementedError (vllm/v1/engine/core_client.py:114-118). So for vllm serve, the engine core is always a separate process.
def make_client(
multiprocess_mode: bool,
asyncio_mode: bool,
vllm_config: VllmConfig,
executor_class: type[Executor],
log_stats: bool,
renderer: BaseRenderer | None = None,
) -> "EngineCoreClient":
# renderer is passed through to the multiprocess clients, which start
# the frontend MM warmup (renderer.start_mm_warmup_in_background) once
# the engine-core processes have been forked, so warmup overlaps
# engine-core load without a live thread at fork() time. In-process
# clients do not take a renderer: the engine core is built in this
# process, so there is no other process to overlap with and the MM
# warmup runs synchronously inside renderer.warmup() instead.
# TODO: support this for debugging purposes.
if asyncio_mode and not multiprocess_mode:
raise NotImplementedError(
"Running EngineCore in asyncio without multiprocessing "
"is not currently supported."
)
if multiprocess_mode and asyncio_mode:
return EngineCoreClient.make_async_mp_client(
vllm_config,
executor_class,
log_stats,
renderer=renderer,
)
if multiprocess_mode and not asyncio_mode:
return SyncMPClient(
vllm_config,
executor_class,
log_stats,
renderer=renderer,
)
return InprocClient(vllm_config, executor_class, log_stats)EngineCoreClient.make_client(): the three client types. AsyncLLM uses the first branch; the LLM class uses one of the other two.Deep diveHardware: built-in platforms and platform plugins
vLLM supports NVIDIA GPUs, AMD GPUs, Intel GPUs and x86, ARM and PowerPC CPUs. It also lists hardware plugins, for example Google TPUs, Intel Gaudi, IBM Spyre and Huawei Ascend (README.md:51).
In the code, each process selects one platform object, current_platform. The selection works like this (vllm/platforms/__init__.py:240-292):
- If
VLLM_TARGET_DEVICEiscpu, the CPU platform wins at once (vllm/platforms/__init__.py:244-248). - vLLM loads the out-of-tree platform plugins of the entry-point group
vllm.platform_plugins(vllm/platforms/__init__.py:250). - It calls every built-in detector and every plugin detector. A detector returns a class name or
None. The five built-in detectors aretpu,cuda,rocm,xpuandcpu(vllm/platforms/__init__.py:231-237). - One active plugin wins over the built-in detectors. Two active plugins, or two active built-in detectors, raise
RuntimeError. No active detector givesUnspecifiedPlatform(vllm/platforms/__init__.py:272-292).
The TPU platform class itself lives in a separate package, tpu_inference (vllm/platforms/tpu.py:9-19). The pages Platform plugins and current_platform and How vLLM finds and loads plugins explain the plugins.
Deep diveWhat is new compared with DeepInfer
DeepInfer "was originally built primarily on vLLM" (DeepInfer Explained). Much of its design looks like a simple vLLM. The table lists the main differences. The vLLM column cites the vLLM code. The page vLLM and DeepInfer compared gives the full comparison.
| Topic | DeepInfer | vLLM at this commit |
|---|---|---|
| How you use it | Offline only: your script calls LLM.generate(), and the engine loop calls step() (Offline API and the step loop) | Online first: vllm serve starts an OpenAI-compatible HTTP server (vllm/entrypoints/cli/serve.py:39-40). The LLM class also exists (vllm/entrypoints/llm.py:341-343). |
| Processes | The engine loop and the driver worker run in your script process; context-parallel followers run in their own processes (Worker) | A front-end process and an engine core process, joined by ZMQ sockets (vllm/v1/engine/core_client.py:672-682); more worker processes with TP > 1 |
| Models | One model, DeepSeek-V4.1-Flash (Model map) | "200+ model architectures" (README.md:53-60), found by architecture name in the model registry (vllm/model_executor/models/registry.py:73, vllm/model_executor/models/registry.py:1565) |
| Hardware | NVIDIA SM100 and Huawei Ascend 950 (NVIDIA and Ascend) | Five built-in platform detectors plus out-of-tree platform plugins (vllm/platforms/__init__.py:231-237, vllm/platforms/__init__.py:250) |
| Scheduler | C++; each step is a prefill batch or a decode batch, never both (The scheduler) | Python; no prefill or decode phase, so one step can mix both (vllm/v1/core/sched/scheduler.py:624-633) |
| KV cache blocks | 128 tokens per block; no prefix cache in the release (Paged KV cache) | Default 16 tokens, which the platform can change for the attention backend (vllm/config/cache.py:182, vllm/platforms/interface.py:771-781). Prefix caching is on by default when the model supports it (vllm/engine/arg_utils.py:3032, vllm/engine/arg_utils.py:3062-3063). |
| Parallelism | DP, CP and EP; no TP and no PP (Parallelism basics) | "Tensor, pipeline, data, expert, and context parallelism" (README.md:45) |
| Plugins | No entry-point groups in its packaging files | Five plugin groups in vllm/plugins/__init__.py (vllm/plugins/__init__.py:16-30) plus vllm.logits_processors (vllm/v1/worker/gpu/sample/logits_processor/loader.py:34) |
torch.compile | Not used | On by default: optimization level O2 gives the mode VLLM_COMPILE (vllm/config/vllm.py:434, vllm/config/vllm.py:1806-1810) |
Deep diveRelease and version numbers
The version is not written in a source file. The build reads it from git tags with setuptools-scm (pyproject.toml:8, pyproject.toml:49-50):
get_vllm_version()callssetuptools_scm.get_version()with the commandgit describe --dirty --tags --long --abbrev=40 --match v[0-9]*(setup.py:26-35,setup.py:1360-1363). It writes the result tovllm/_version.py.- It adds a local suffix for the build target (
setup.py:1364-1400).VLLM_SKIP_VERSION_SUFFIXturns this off. The suffixes are+precompiled,+cu<ver>when the CUDA version is not the main one,+rocm<ver>,+tpu,+cpu,+xpuor+empty. The main CUDA version is13.0by default (vllm/envs.py:624-626). VLLM_VERSION_OVERRIDEreplaces the whole version (setup.py:1352-1358).- At run time,
vllm/version.pyimports__version__from_version.py. When that fails, it warns and uses"dev"(vllm/version.py:4-12).
Worked example. At the pinned commit, the git describe command of setup.py gives v0.32.1rc0-307-g3e44c0db26.... That is the tag v0.32.1rc0, then 307 commits, then g and the commit hash. The hash has all 40 hex digits, because of --abbrev=40. So this code comes after the 0.32.1 release candidate 0. The exact string that setuptools-scm makes from this (a .dev307 version with the hash) depends on that library and is not in the vLLM repository.
You can read the version in three places. vllm --version reads the installed package metadata (vllm/entrypoints/cli/main.py:92-97). GET /version on a running server returns {"version": ...} (vllm/entrypoints/serve/instrumentator/basic.py:53-56). Python code reads vllm.__version__ (vllm/__init__.py:7).
Deep diveTwo parts with one paragraph each: the Rust front end and vllm/models/
The Rust front end. The folder rust/ holds "a Rust drop-in alternative frontend for vLLM". It talks to the Python engine core processes "via ZMQ over the existing engine boundary", and its README calls it "experimental" and "not feature-complete" (rust/README.md:3-5). VLLM_USE_RUST_FRONTEND=1 turns it on; the default is off (vllm/envs.py:1452-1456). Then vllm serve starts the Rust binary instead of the Python API server processes (vllm/entrypoints/cli/serve.py:346-361). This site does not explain it further.
The per-family model packages. Besides vllm/model_executor/models/, there is a second model tree, vllm/models/, with one package per model family, for example deepseek_v4 and qwen4_exp (vllm/models/). The model registry points some architecture names to these packages, for example "DeepseekV4ForCausalLM": ("vllm.models.deepseek_v4", ...) (vllm/model_executor/models/registry.py:99). This site uses llama.py as its one model example and does not explain these packages.
What can go wrong#
- Old tutorials. A tutorial that says "V0",
--use-v2-block-managerorAsyncLLMEngineinternals describes code that is gone. The two old class names still import, but they are V1 classes (vllm/engine/async_llm_engine.py:6,vllm/engine/llm_engine.py:6). - Offline and online defaults differ. The
LLMclass turns statistics off by default (vllm/entrypoints/llm.py:225-226). It also gets other scheduler defaults thanvllm serve, because the usage context differs (vllm/entrypoints/llm.py:341-343,vllm/engine/arg_utils.py:2960-2993). A benchmark withLLMdoes not tell you howvllm servebehaves. - No platform found. When no detector is active, vLLM uses
UnspecifiedPlatform(vllm/platforms/__init__.py:290-292), and later code fails. Check that the right GPU drivers or the platform plugin package are installed. - Two platform plugins. Two installed and active platform plugins stop start-up with
RuntimeError(vllm/platforms/__init__.py:272-276). - A version string of
dev. Ifvllm/_version.pyis missing (for example, a source tree that was never built), the version is"dev"with a warning (vllm/version.py:6-12).
Why it matters. Know your entry point and its processes. Then you know which pages of this site apply to you, and which process owns each flag and each log line.
Check yourself#
- 1Which command starts the OpenAI-compatible server, and which Python function does it call first?easy
Show answer
vllm serve. The console scriptvllmcallsvllm.entrypoints.cli.main:main(pyproject.toml:42-43), which dispatches to theservesubcommand (vllm/entrypoints/cli/main.py:116-117). - 2An old example importseasy
AsyncLLMEngine. Which class does it get?Show answer
The V1
AsyncLLM. The module only contains the aliasAsyncLLMEngine = AsyncLLM(vllm/engine/async_llm_engine.py:4-6). - 3You setmedium
VLLM_ENABLE_V1_MULTIPROCESSING=0and startvllm serve. Does the engine core now run inside the API server process?Show answer
No.
AsyncLLMalways callsmake_async_mp_client(vllm/v1/engine/async_llm.py:193). The variable only changes theLLMEngineof the offlineLLMclass (vllm/v1/engine/llm_engine.py:186-188). - 4A machine has an NVIDIA GPU and you install one out-of-tree platform plugin whose detector also returns a class name. Which platform does vLLM select, and what happens with two such plugins?hard
Show answer
The plugin platform: when exactly one out-of-tree plugin is active, it wins over the built-in CUDA detector (
vllm/platforms/__init__.py:277-279). With two active plugins, start-up stops withRuntimeError("Only one platform plugin can be activated ...")(vllm/platforms/__init__.py:272-276). - 5You build vLLM from source with CUDA 12.9 at this commit. Which suffix does the version get, and why?hard
Show answer
+cu129, unlessVLLM_SKIP_VERSION_SUFFIXis set or the build uses precompiled extensions. The CUDA version 12.9 is not the main version13.0(vllm/envs.py:624-626). So the build addscuand the first three digits of the version without dots (setup.py:1376-1382).