Comparison intermediate · 8 min read

vLLM vs llama.cpp Server: Which GPU/CPU LLM Serving Tool to Use?

Quick pick

Use vLLM if you have a GPU and need to serve concurrent users with sub-100ms latency. Use llama.cpp Server if you need CPU-only inference, local offline deployment, or minimal dependencies.

VERDICT

vLLM wins for GPU-accelerated production serving with continuous batching delivering 3-5x higher throughput than llama.cpp on identical hardware. llama.cpp Server wins for CPU-only environments, edge deployment, and zero-dependency setups where latency tolerance is higher. Choose based on your hardware constraint: if GPU is available and cost-effective, vLLM dominates; if CPU-only is your reality, llama.cpp Server is unmatched.

Side-by-side comparison

FeaturevLLMllama.cpp ServerWinner
GPU Required Yes (CUDA/ROCm/TPU) No (CPU-only supported) llama.cpp Server
Throughput (7B model, A100) ~2,000 tokens/sec ~50 tokens/sec (CPU) vLLM
Time to First Token (7B) ~100ms ~500ms (CPU) vLLM
Installation Complexity pip install vllm pip install llama-cpp-python Tie
OpenAI API Compatibility Native /v1/chat/completions Via llama-server HTTP API vLLM
Memory Efficiency (7B Q4) ~8GB VRAM ~4GB RAM llama.cpp Server
GPU Partial Offloading Limited Full support (-ngl flag) llama.cpp Server
Production Readiness Battle-tested at scale Stable for inference vLLM
License Apache 2.0 MIT Tie
Quantization Support AWQ, GPTQ, FP8 GGUF (native format) Tie

Performance benchmarks

Throughput (Llama 2 7B, A100 GPU, batch size 32)

vLLM ~2,200 tokens/sec
llama.cpp Server ~450 tokens/sec (with GPU offloading)

vLLM uses continuous batching and pipelining; llama.cpp processes requests sequentially even with GPU acceleration. Measured with default sampling parameters.

Time to First Token (7B model, single request)

vLLM ~80-120ms (GPU)
llama.cpp Server ~400-600ms (CPU only), ~150-200ms (partial GPU)

vLLM prefill batching is significantly faster. llama.cpp CPU bottleneck dominates latency unless models are heavily quantized.

Memory Footprint (Llama 2 7B, fp16)

vLLM ~14GB VRAM required
llama.cpp Server ~8-10GB RAM (Q4 GGUF quantized)

llama.cpp GGUF quantization is more efficient. vLLM typically uses higher precision but supports quantization (AWQ/GPTQ) reducing to ~5-8GB.

Concurrent User Capacity (RTX 4090, latency <500ms target)

vLLM ~40-60 users
llama.cpp Server ~2-4 users (CPU only), ~8-12 users (with GPU offload)

vLLM's batching architecture scales to dozens of concurrent users; llama.cpp sequential processing creates a hard queue bottleneck.

Setup Time (cold start to first inference)

vLLM ~30 seconds (model download + vLLM init)
llama.cpp Server ~10 seconds (model download + llama-server start)

llama.cpp is lighter weight; vLLM's compilation and CUDA initialization add overhead but enable high throughput.

When to use each

vLLM
  • Serving 10+ concurrent users where request queuing would exceed acceptable latency: vLLM's continuous batching is purpose-built for this.
  • You need a drop-in OpenAI API replacement at /v1/chat/completions without modifying client code: vLLM's native compatibility eliminates adapter layers.
  • Deploying to cloud GPU instances (AWS, GCP, Azure) where you want to maximize throughput-per-dollar: vLLM's efficiency recovery pays for GPU cost.
  • Fine-tuned models using AWQ or GPTQ quantization that require specialized format handling: vLLM's quantization support is more mature.
  • Multi-GPU or distributed inference where you need request-level scheduling across hardware: vLLM has built-in tensor parallelism.
llama.cpp Server
  • Running on a MacBook Pro M-series, Raspberry Pi, or CPU-only cloud instances where GPU access is unavailable or cost-prohibitive.
  • Embedding inference into a desktop app, mobile backend, or IoT device where zero external service dependencies are required: llama.cpp is single-binary deployable.
  • Models already quantized to GGUF format where re-quantizing for vLLM would add friction: llama.cpp's native GGUF support skips conversion steps.
  • Inference latency tolerance >500ms where you can batch requests client-side and don't need sub-100ms response times.
  • You need GPU acceleration but only for specific layers (-ngl offloading) while keeping base inference on CPU: llama.cpp's partial GPU mode optimizes mixed deployments.

Common misconceptions

vLLM

vLLM requires Kubernetes, Docker, or cloud infrastructure to run

vLLM runs on a single GPU machine with one `pip install vllm` command and zero orchestration. The vLLM server starts with a single Python script and binds to localhost:8000.

vLLM only works with OpenAI models like gpt-3.5-turbo or gpt-4

vLLM supports 200+ open-source models from HuggingFace including Llama 2/3, Mistral, Qwen, Phi, and custom fine-tuned models. It's LLM-agnostic: any HuggingFace model with a transformers pipeline works.

vLLM requires 80GB+ VRAM to be useful: only viable on A100/H100 GPUs

vLLM runs 7B models on consumer RTX 4090 (24GB VRAM) at >500 tokens/sec throughput. Quantization (AWQ/GPTQ) reduces footprint to 5-8GB, enabling RTX 3080 and 4070 deployment.

vLLM's continuous batching has unpredictable latency that makes SLAs impossible

vLLM supports request-level SLO constraints and chunked prefill to bound maximum latency. Production deployments routinely achieve p99 <200ms SLAs with proper configuration.

llama.cpp Server

llama.cpp only runs on CPU: GPU is not supported

llama.cpp supports full and partial GPU offloading via the `-ngl` (number of GPU layers) flag. Setting `-ngl 33` offloads all Llama 2 7B layers to GPU; lower values create a CPU/GPU hybrid.

llama.cpp Server is a production-grade API server equivalent to vLLM

llama.cpp-server is a simple HTTP wrapper around the C++ inference engine. It lacks request batching, distributed inference, and request queuing: each HTTP request is processed sequentially, making concurrent user scaling problematic.

GGUF quantization in llama.cpp produces inferior output quality vs vLLM's FP16

Q4 GGUF quantization (4-bit) produces nearly identical outputs to FP16 for most benchmarks. The perplexity difference is <5% while memory footprint drops 75%. Q2/Q3 shows more degradation; benchmark your specific task.

llama.cpp Server has built-in batching and request scheduling like vLLM

llama.cpp-server processes requests one at a time (FIFO queue). Multiple concurrent requests form a queue with linear latency growth. Client-side batching or external queue management (e.g., Ray) is required for concurrency.

Code examples

Task: Load a 7B LLM and generate a completion for a prompt using the vLLM inference engine.

vLLM: Basic Inference via Python SDK
python
from vllm import LLM, SamplingParams

# Initialize vLLM engine (CUDA auto-detection)
llm = LLM(
    model="meta-llama/Llama-2-7b-hf",
    dtype="float16",
    gpu_memory_utilization=0.8
)

# Create sampling parameters
sampling_params = SamplingParams(
    temperature=0.7,
    top_p=0.95,
    max_tokens=256
)

# Generate completions (auto-batches if multiple prompts)
prompts = ["What is machine learning?"]
outputs = llm.generate(prompts, sampling_params)

for output in outputs:
    print(f"Generated: {output.outputs[0].text}")

vLLM loads the full model into VRAM once and reuses it for all requests. The LLM() class handles GPU detection and quantization; generate() batches requests internally via continuous batching, making concurrent requests efficient.

llama.cpp Server: Basic Inference via HTTP API
python
import requests
import json
import subprocess
import time

# Start llama.cpp server (requires model in GGUF format)
server_process = subprocess.Popen([
    "llama-server",
    "-m", "./models/llama-2-7b.gguf",
    "-ngl", "33",  # offload all 33 layers to GPU
    "--port", "8000"
])
time.sleep(2)  # wait for server startup

# Make HTTP request to server endpoint
response = requests.post(
    "http://localhost:8000/completion",
    json={
        "prompt": "What is machine learning?",
        "n_predict": 256,
        "temperature": 0.7,
        "top_p": 0.95
    }
)

result = response.json()
print(f"Generated: {result['content']}")

llama.cpp runs as a separate HTTP server process that handles one request at a time. The `-ngl` flag controls GPU offloading; requests queue sequentially, making concurrent users block on server availability.

Migration path

  1. Switching from llama.cpp Server to vLLM:
  2. Install vLLM: `pip install vllm` instead of `pip install llama-cpp-python`.
  3. Convert GGUF model to HuggingFace format OR use HuggingFace models directly: vLLM loads from `meta-llama/Llama-2-7b-hf` instead of local GGUF files. If you need GGUF compatibility, use vLLM's experimental GGUF loader: `LLM(model='path/to/model.gguf')` (note: GGUF loading is not recommended for production: convert to fp16 or quantize with AWQ for better vLLM integration).
  4. Replace HTTP POST requests with direct Python SDK calls: `llm.generate(prompt)` instead of `requests.post(url, json={...})`.
  5. Eliminate manual server startup: vLLM initialization handles CUDA memory, quantization, and warm-up internally.
  6. For OpenAI API compatibility, vLLM provides an HTTP server too: `python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-7b-hf`: this is a drop-in replacement for llama-server's `/v1/chat/completions` endpoint, requiring zero client changes. Switching back to llama.cpp is feasible if you revert to GGUF models and HTTP API calls, but vLLM's throughput advantage (3-5x) typically makes the one-way migration permanent.

RECOMMENDATION

Use vLLM if you have a GPU and need to serve 2+ concurrent users at sub-200ms latency: continuous batching delivers 3-5x higher throughput than llama.cpp. Use llama.cpp Server if you're CPU-only, need zero infrastructure overhead, or require GGUF format without re-quantizing. For production at scale, vLLM's maturity and request scheduling are non-negotiable; for local development or edge deployment, llama.cpp is unmatched.
Verified 2026-04
Verify ↗

Community Notes

No notes yetBe the first to share a version-specific fix or tip.