llama.cpp: build, run and serve
Install or build llama.cpp for CUDA, Metal, Vulkan or ROCm, use llama-cli and llama-server, learn the flags you will use daily (context, offload, slots, threads, flash attention), try the web UI and API and fix the common problems.
Older tutorials use
./main. That binary was renamed tollama-cli(and./servertollama-server) in 2024. If a command in a blog post does not exist, the name is probably outdated.
llama.cpp is the engine behind much of the local-LLM ecosystem. Running it directly gives you the most control and the most information about what is happening. You can install a prebuilt binary in a minute, or build it to match your hardware.
#Install the easy way
brew install llama.cpp # macOS / Linux with Homebrew
# or download prebuilt binaries from the project's GitHub releases
# (pick the build for your OS and GPU backend: CUDA, Vulkan, Metal, CPU)Prebuilt binaries are fine for most people. Build from source when you need a specific backend, the very latest model support or custom options.
#Build from source
git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp
cmake -B build # macOS: Metal is on by default
# NVIDIA: cmake -B build -DGGML_CUDA=ON
# Vulkan: cmake -B build -DGGML_VULKAN=ON
# AMD: cmake -B build -DGGML_HIP=ON
cmake --build build --config Release -jBinaries land in build/bin/. Requirements: a C++ compiler, CMake, and for GPU backends the matching toolkit (CUDA Toolkit, Vulkan SDK or ROCm). Flag names occasionally change, so check the build instructions in the repository's README for your version.
| Backend | Hardware | Notes |
|---|---|---|
| Metal | Apple Silicon | On by default on macOS |
| CUDA | NVIDIA GPUs | Fastest on NVIDIA; needs the CUDA toolkit |
| Vulkan | Most GPUs (AMD, Intel, NVIDIA) | Portable; often a bit slower than the native backend |
| HIP / ROCm | AMD GPUs | Support depends on card and OS |
| SYCL | Intel GPUs | |
| CPU | Anything | Use AVX2 or AVX-512 builds on x86, NEON on ARM |
A quick way to confirm the backend: start a model with -ngl 99 and read the log. It says how many layers were offloaded and to which device. If it reports 0 layers, you built a CPU-only binary or the flag is missing.
#The toolbox
| Binary | Purpose |
|---|---|
llama-cli |
Interactive chat / one-shot generation |
llama-server |
OpenAI-compatible HTTP server + web UI |
llama-bench |
Speed benchmarks (pp/tg) (benchmark lab) |
llama-perplexity |
Quality measurement (measuring quality) |
llama-quantize |
Convert F16 GGUF to quantized (GGUF) |
llama-tokenize |
Count and inspect tokens |
llama-embedding |
Generate embeddings |
llama-imatrix |
Build importance matrices for low-bit quants |
#Run
# Chat, pulling a model from Hugging Face on first use
llama-cli -hf bartowski/Meta-Llama-3.1-8B-Instruct-GGUF:Q4_K_M -ngl 99 -c 8192
# Serve on http://localhost:8080 (web UI included)
llama-server -hf bartowski/Meta-Llama-3.1-8B-Instruct-GGUF:Q4_K_M \
-ngl 99 -c 16384 --port 8080Downloaded files are cached (the location depends on OS and version). You can also point at a file: -m /path/model.gguf.
After the server starts, open http://localhost:8080 for the chat UI, or call it:
curl http://localhost:8080/v1/chat/completions -H "Content-Type: application/json" -d '{
"model": "local",
"messages": [{"role": "user", "content": "Name three uses of a KV cache."}],
"max_tokens": 200
}'
curl http://localhost:8080/health # readiness checkThe server speaks the OpenAI API, so any compatible client works (serving).
#The flags you will use daily
| Flag | Meaning |
|---|---|
-m FILE / -hf REPO:QUANT |
Model file or Hugging Face repo |
-c N |
Context size (tokens) |
-ngl N |
Layers to offload to the GPU (99 = all) |
-t N |
CPU threads (match physical cores) |
-np N |
Parallel slots (context is divided among them) |
--jinja |
Use the model's Jinja chat template (needed for tools) |
-fa |
Flash attention (newer builds take on, off or auto) |
-b, -ub |
Batch and micro-batch size (affects prompt processing speed and memory) |
--temp, --top-p, --min-p |
Sampling (sampling) |
--host, --port |
Where the server listens (default 127.0.0.1:8080) |
--api-key KEY |
Require a bearer token |
--metrics |
Prometheus metrics at /metrics |
-ctk, -ctv |
KV cache type (for example q8_0) (KV cache) |
--mlock, --no-mmap |
Keep weights in RAM; disable memory-mapping |
--tensor-split |
Split layers across several GPUs |
Run llama-server --help for the full list for your version; it is long, and options evolve. Generate commands interactively with the command builder.
#Context, slots and memory
-c is the total context across all slots, and -np slots share it:
-c 32768 -np 4 -> each slot gets 8,192 tokensKV cache memory grows with -c (VRAM math); all of it is reserved when the server starts, so a too-large -c shows up immediately as an out-of-memory error rather than later. Slots matter for throughput under load (concurrency).
#Offloading and partial fits
-ngl 99 puts every layer on the GPU. If the model does not fit, lower -ngl (for example -ngl 24) to keep the rest on the CPU. It works, but each CPU layer runs at system-memory speed, so prefer a smaller quant or a shorter context first (GPU offload).
#Threads
-t matters for CPU inference and for any layers left on CPU. Match your physical core count; hyper-threads rarely help, because decode is bound by memory bandwidth, not by instruction throughput.
#Safe defaults for a first server
llama-server -m model.gguf -ngl 99 -c 8192 -np 2 \
--host 127.0.0.1 --port 8080 --jinjaKeep --host 127.0.0.1 until you have put authentication and TLS in front (production endpoint lab); the server has only a basic API-key option.
#Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| GPU idle, slow generation | CPU-only build or -ngl 0 |
Rebuild with the backend flag; pass -ngl 99 |
| "failed to allocate" or out-of-memory | Context or model too large | Lower -c, use a smaller quant, quantise the KV cache |
| "unknown model architecture" | llama.cpp too old for this model | Update or rebuild |
| Garbled output, never stops | Wrong or missing chat template | Add --jinja; check the model card |
| Slower than expected on CPU | Wrong thread count or no AVX | -t = physical cores; use an optimised build |
| Tool calls come back as plain text | Missing --jinja or an unsuitable model |
Use --jinja and a tool-capable model (function calling) |
| Port already in use | Another server on 8080 | Change --port |
| Very slow first request | Model loading and warm-up | Normal; keep the server running |
#Common mistakes
- Following old tutorials that use
./main,./serveror removed flags. - Forgetting
-ngl, then wondering why the GPU is unused. - Setting
-chuge "just in case", then running out of memory. - Using all logical threads instead of physical cores.
- Binding to
0.0.0.0without authentication. - Comparing speed without noting quant, context and flags.
#Exercise
You have a 12 GiB GPU and want to serve a 14B model (Q4_K_M, about 8.3 GiB) to two users, each with 8K context (KV about 192 KiB per token).
- What
-cand-npdo you use? - Does it fit?
Answers:
-np 2and-c 16384(2 ร 8,192).- KV is
16,384 ร 192 KiB = 3 GiB. Total with 8.3 GiB of weights and about 1 GiB of overhead is about 12.3 GiB, which does not fit in 12 GiB. Options: quantise the KV cache (-ctk q8_0 -ctv q8_0with flash attention, saving about 1.5 GiB), reduce to 6K context per slot, or use a smaller quant.
Quick quiz
+10 XP per correct answer, +25 XP for a perfect score
1. Which binary starts an HTTP server with a web UI?
2. Which flag offloads layers to the GPU?
3. You run llama-server with -c 32768 -np 4. How much context does each slot get?
4. How many threads should -t normally match?
5. You build llama.cpp and it runs, but generation is slow and the GPU sits idle. What is the likely cause?