On a MSI RTX 3060 12GB in 2026, llama.cpp is fractionally faster than Ollama on identical models, because Ollama is a managed wrapper over llama.cpp's inference engine. The real question is not raw speed — it's who owns the tuning. Pick Ollama if you want a two-command install and sensible defaults. Pick llama.cpp when you need to control quantization, context length, thread count, or extract the last 5–10% of throughput.
Two runners, same engine, different feel
Both projects have won a wide audience in the local-LLM community, and both run natively on the 12GB RTX 3060. But the two land in very different places on the ease-versus-control axis.
llama.cpp is the low-level runtime. It compiles from C++ source, exposes every flag from thread count to CUDA graph capture, and lets you pick your own quantization on your own weights. If you want to run a q6 model with a 16K context window and pinned CPU offload, llama.cpp lets you say so. The tradeoff: you write the shell scripts, you pick the quantizations, and you handle the model files yourself.
Ollama is the managed wrapper. Under the hood it uses llama.cpp's inference engine on most builds, but it hides the flags behind a friendly CLI and a small daemon that manages a model registry. ollama run llama3 pulls a preset quantization, starts the server, and gives you an interactive chat. For a lot of users — especially anyone who wants an OpenAI-compatible endpoint on localhost:11434 for their app — Ollama is exactly what they need.
This piece compares both on the same RTX 3060 12GB rig with a Ryzen 7 5800X CPU, using community-measured throughput numbers to keep the comparison honest.
Key takeaways
- Ollama runs llama.cpp's engine internally on most builds — the raw speed gap is small.
- llama.cpp wins on tuning depth: pick your quantization, threads, context length, CPU offload.
- Ollama wins on setup speed and application integration (OpenAI-compatible endpoint out of the box).
- On a RTX 3060 12GB, 7B q4 models push 60–80 tokens per second; 13B q4 lands around 25–35.
- Both benefit from fast storage for model loading — the Samsung 970 EVO Plus matters, Crucial BX500 is fine as archive.
What each tool is, in one line
- llama.cpp: C++ inference engine + CLI + server, GGUF model format, works on CUDA/Metal/Vulkan/CPU.
- Ollama: Go daemon + CLI wrapper around llama.cpp (and other engines), model registry, HTTP API.
The engine underneath is often the same, but the surface you interact with is entirely different.
Feature-delta table
| Dimension | llama.cpp | Ollama |
|---|---|---|
| Install effort | Build from source or precompiled binary | One-line installer |
| Model format | GGUF (choose quantization yourself) | Preset Modelfile (opinionated defaults) |
| CUDA support | Yes | Yes |
| Vulkan / ROCm | Yes | Partial |
| Context length | Any (set via flag) | Preset (edit Modelfile) |
| Thread count control | Fine-grained | Coarse |
| Batch/prefill tuning | Direct flags | Not exposed |
| Server API | OpenAI-compatible option | OpenAI-compatible default |
| Model registry | Manual (you download GGUF) | Managed (ollama pull) |
| Setup for beginners | Moderate | Trivial |
| Setup for tinkerers | Ideal | Feels restrictive |
Ollama's opinionated defaults are usually reasonable. But when they aren't — say, when your workload wants a 32K context on a 13B model and Ollama's default is 8K — you either edit a Modelfile or drop down to llama.cpp anyway.
Benchmark table: throughput on RTX 3060 12GB
Community measurements aggregated from r/LocalLLaMA, GitHub issues, and llama.cpp CI runs, using the CUDA backend on a 12GB RTX 3060. Numbers are approximate; your build flags, driver version, and background load all move the number by ±10%.
| Model | Precision | llama.cpp tok/s | Ollama tok/s | Notes |
|---|---|---|---|---|
| Llama 3.1 8B | q4_K_M | 68–78 | 65–75 | Nearly identical |
| Llama 3.1 8B | q5_K_M | 55–65 | 52–62 | Marginal Ollama tax |
| Mistral 7B | q4_K_M | 72–82 | 70–80 | Very close |
| Qwen 2.5 14B | q4_K_M | 28–35 | 26–33 | 13B tier holds up |
| Qwen 2.5 32B | q4_K_M | 4–8 | 3–7 | CPU offload |
llama.cpp wins by roughly 3–5% on most workloads. The gap comes from Ollama's added HTTP layer plus its default preset choices — not from any inefficiency in the underlying engine. When Ollama configures llama.cpp identically (same threads, same context, same batch size), the numbers converge.
How much overhead does Ollama add?
Two places:
HTTP surface. Ollama exposes an OpenAI-compatible REST endpoint. Every request roundtrips through JSON serialization and HTTP framing before hitting the inference engine. On short prompts and streaming outputs this cost is invisible — maybe 5–20 ms per call. On large batch workloads it becomes measurable.
Preset defaults. Ollama's default thread count for CPU offload on Zen 3 is sometimes suboptimal. Ollama's default context window is often smaller than what fits in VRAM. Both are fixable by editing a Modelfile, but the friction is real if you didn't know to look.
For a single user chatting interactively, none of this matters. For a batch pipeline that fires thousands of calls per hour, the differences compound. That is when llama.cpp direct starts to win by a bigger margin.
Quantization matrix on RTX 3060
| Format | Bits/weight | 7B fit | 13B fit | 32B fit | Tok/s ratio (7B) |
|---|---|---|---|---|---|
| fp16 | 16 | overflow | no | no | n/a |
| q8 | 8 | tight | overflow | no | 0.80x |
| q6_K | 6 | yes | overflow | no | 0.90x |
| q5_K_M | 5 | yes | tight | no | 0.95x |
| q4_K_M | 4 | yes | yes | with offload | 1.00x |
| q3_K_M | 3 | yes | yes | tight | 1.10x |
| q2_K | 2 | yes | yes | yes | 1.25x |
Ratios apply similarly to both runners. Sweet spot at 12GB is q4_K_M for both 7B and 13B; drop to q3 only to shoehorn a bigger model into memory.
Context-length impact: KV-cache growth on 12GB
Every token in your context consumes KV-cache VRAM proportional to model width. Rough numbers on a 13B model at q4:
| Context window | KV cache | Total VRAM (weights + KV) |
|---|---|---|
| 4K | ~1.2 GB | ~10 GB |
| 8K | ~2.4 GB | ~11 GB |
| 16K | ~4.8 GB | ~13 GB (overflow) |
| 32K | ~9.6 GB | ~18 GB (heavy offload) |
12GB is comfortable for 4K–8K context on 13B models. Push to 16K and you either need a smaller model, a shorter context, or CPU offload — which crashes speeds because generation now bottlenecks on system RAM bandwidth.
llama.cpp lets you set --ctx-size 8192 directly. Ollama needs a Modelfile edit or a num_ctx parameter. Both work; llama.cpp is a smaller diff.
Which pairs best with a Ryzen 7 5800X CPU-offload fallback?
Both do. But llama.cpp exposes the offload count directly via --n-gpu-layers. On a 32B model that doesn't fit in 12GB, you can push, say, 40 of 60 layers to the GPU and let the Ryzen 7 5800X handle the rest on system memory. That gives you working throughput on models the GPU alone can't hold.
Ollama supports offload too, via the num_gpu Modelfile parameter, but the default preset is coarser. For workloads that need to squeeze a 32B model into a 12GB card, llama.cpp is more productive.
For a fallback CPU-only rig (say, a build around a Ryzen 5 5600G with no discrete GPU), both work but llama.cpp's -t flag for thread count is more visible. Ollama defaults are usually OK but not tuned.
Storage: does the drive matter?
Model files are big. A 13B q4 GGUF is ~9 GB; a 32B q4 is ~19 GB. Model load times differ:
- Samsung 970 EVO Plus 250GB NVMe — 13B q4 loads in ~2 seconds
- Crucial BX500 1TB SATA — 13B q4 loads in ~5 seconds
- Spinning HDD — 30+ seconds, do not do this
Both runners benefit equally. Keep active models on the NVMe, archive quantizations on the BX500.
Real-world numbers: prefill vs generation
Two phases of inference have different performance profiles, and the runner choice affects each differently.
Prefill (encoding your prompt): compute-bound. On a 3060 running Llama 3.1 8B q4, prefill throughput lands near 900–1,200 tokens/second on llama.cpp and ~800–1,050 on Ollama. That is why a 4,000-token prompt takes ~4 seconds to encode before the first output token appears — and why Ollama's small overhead is more noticeable here than during generation.
Generation (emitting one token at a time): memory-bandwidth-bound. Here the runner matters less; both hit the same VRAM-bandwidth ceiling. Community measurements show llama.cpp at 68–78 tokens/sec and Ollama at 65–75 tokens/sec on 8B q4 — a gap under 5%.
For batch pipelines with long prompts, llama.cpp's prefill advantage compounds. For interactive chat with short prompts, the difference is invisible.
Multi-model routing: where Ollama pulls ahead
If you regularly swap between three or four models — a coding-focused fine-tune, a general chat model, an embedding model — Ollama's model registry is genuinely helpful. ollama list shows what's installed; ollama pull llama3 grabs a new preset in seconds; the daemon hot-swaps models without an explicit unload.
llama.cpp forces you to track model files yourself and rebuild command-line invocations for each. That is fine for a single-model workflow but tedious across many. If your app calls into several specialized models daily, Ollama's model-management story alone can justify the small throughput cost.
Common pitfalls
Assuming Ollama is "just slower." It usually isn't — the underlying engine is the same. If you see a large gap, you have a default mismatch (context, threads) rather than an actual engine issue.
Running Ollama with the daemon-provided context length on a workload that needs more. Edit the Modelfile once and move on.
Forgetting to pass --n-gpu-layers all in llama.cpp. By default some builds don't offload everything. Check with nvidia-smi.
Mixing runtimes in one project. Pick one for a workflow; don't hop back and forth debugging tiny throughput deltas.
Running Ollama's HTTP endpoint from every language layer. For low-latency workloads, call llama.cpp's C API directly, or use a Python binding — HTTP roundtrips add up.
Bottom line
For a first local-LLM setup, install Ollama. It works, it is fast enough, and it drops an OpenAI-compatible endpoint on :11434 that most apps can talk to today. For serious tuning — squeezing a 32B model into a 12GB card, running batch pipelines at scale, testing exotic quantizations, or maximizing tokens per second for a chat interface — reach for llama.cpp direct.
Most users end up with both installed. Ollama handles the "just make it work" cases; llama.cpp handles the "I need this exact configuration" cases. On a RTX 3060 12GB rig they share the same engine, and the choice is more about your workflow than about raw speed.
Verdict matrix
| Situation | Recommendation |
|---|---|
| First local-LLM setup, want interactive chat | Ollama |
| Need OpenAI-compatible endpoint fast | Ollama |
| Squeezing 32B models into 12GB | llama.cpp |
| Batch pipeline hitting thousands of calls | llama.cpp |
| Prefer explicit config files | llama.cpp |
| Want package-manager-style model registry | Ollama |
| Running on Vulkan (no CUDA) | llama.cpp |
| Testing custom quantizations | llama.cpp |
Related guides
- Local LLM on the Ryzen 5 5600G iGPU — no-GPU starter
- Grok 4.5, GPT-5.6, Kimi K3: four frontier models
- Local RTX 3060 rig vs Kimi K3 API cost math
- /benchmarks/geforce-rtx-3060 — RTX 3060 spec + benchmark page
Citations and sources
This piece is editorial synthesis based on publicly available information. No independent first-party benchmarking is reported.
