Backends vLLM llama.cpp Comparison

Backend Comparison

llmux drives two engines from one dashboard, but they are built for different jobs. vLLM serves Hugging Face Transformers models for high-throughput inference; llama.cpp serves GGUF models with fine-grained control over quantization and CPU/GPU placement. This page lays out the feature differences and a "when to use which" guide.

Feature matrix

FeaturevLLMllama.cpp
Model formatHF Transformers (safetensors)GGUF
Container imagevllm/vllm-openaighcr.io/ggml-org/llama.cpp:server-cuda
In-container port80008080
Multi-GPU tensor parallelismYes (gpu_id: "0,1" + tensor_parallel_size)No (single-GPU device list)
GPU passthrough mechanismruntime: nvidia + NVIDIA_VISIBLE_DEVICESdeploy.resources device-id list
LoRA adaptersYes (enable_lora + docker-compose.lora.yaml mount)No
KV cache precision controlNoYes (cache-type-k / cache-type-v)
CPU/GPU layer offloadNoYes (n-gpu-layers)
MoE expert CPU offloadNoYes (override-tensors, regex → CPU)
Speculative / multi-token decodingYes via MTP (dev build + MTP GGUF + extra-args)
Model auto-downloadHF cache (engine downloads)HF cache (-hf/-hff, engine downloads)
Host hf CLI requiredNoNo
Image source options5 (Local Latest / Official Release / Nightly / Dev Build / Custom Tag)3 (Default Image / Dev Build / Custom Tag)
Refuses :latest aliasYes— (single official tag)
In-container version verificationYes (vllm.__version__ checked after start)No
Dev build from sourceYes (vllm-dev:<tag>, docker/Dockerfile)Yes (llamacpp-dev:<tag>, .devops/cuda.Dockerfile)
Extra pip packages at startYes (extra_pip_packages)No
Per-profile env var overridesYes (env_vars)No
Command injection methodCompose command: with --config flagPer-profile override file from render-override.py
Post-start health probe/v1/models returns a served model id/health responds
Cross-backend conflict gateYes (port + GPU overlap, both backends)Yes (port + GPU overlap, both backends)
Built-in OpenAI-compatible benchmarkYesYes

Why the image-source counts differ

The asymmetry — vLLM has five image sources, llama.cpp has three — is intentional, not an oversight.

In other words, both backends expose exactly the choices their upstream registry actually offers.

Why only vLLM does multi-GPU

vLLM's container uses runtime: nvidia with NVIDIA_VISIBLE_DEVICES=${GPU_ID}, so a gpu_id of "0,1" exposes both GPUs and tensor_parallel_size: 2 shards the model across them. llama.cpp's container uses Compose's deploy.resources.reservations.devices device-id list, which cannot reliably expand a comma-separated value into a multi-GPU list. Tensor parallelism is a core vLLM feature, so llmux keeps the two engines on the GPU-passthrough mechanism each one needs rather than forcing a single format.

When to use which

Use vLLM when...

  • You want to run a model straight from its Hugging Face Transformers repo (safetensors weights, no separate quantization step).
  • You need multi-GPU tensor parallelism to fit or speed up a large model.
  • You want to attach LoRA adapters at serve time.
  • You need a specific, verifiable engine version (llmux checks vllm.__version__ inside the container after start).
  • You want high-throughput batched serving and are happy with full/half-precision weights on the GPU.

Use llama.cpp when...

  • Your model is a GGUF (or you want quantized inference: Q4/Q5/Q8).
  • The model is too large for VRAM and you need CPU/GPU layer offload (n-gpu-layers).
  • You are running a MoE model and want to push expert tensors to system RAM with override-tensors while keeping attention on the GPU.
  • You want to squeeze context length out of a fixed VRAM budget by quantizing the KV cache (cache-type-k / cache-type-v).
  • You want to experiment with MTP / multi-token prediction (via a dev build and an MTP-enabled GGUF).

Both backends speak the OpenAI-compatible API, render from the same profiles.yaml, and share the cross-backend conflict gate and the built-in benchmark — so you can run a vLLM and a llama.cpp profile side by side and A/B test them with the identical request protocol.

See also