What the KV-cache is, in one paragraph

A transformer generates one token at a time, and each new token "attends" to every previous token. Without a cache, producing token 1,000 would mean recomputing the key and value vectors for the 999 tokens before it โ€” every single step. The KV-cache stores those key/value vectors so each is computed once and reused. It's the single optimization that makes generation practical โ€” and the price is memory that grows with every token in the context.

The formula

KV-cache bytes = 2 ร— context_length ร— n_layers ร— n_kv_heads ร— head_dim ร— bytes_per_value ร— batch

Reading each term:

  • 2 โ€” one set for keys, one for values.
  • context_length โ€” tokens held in context. This is the term you control, and it scales the whole thing linearly.
  • n_layers ร— n_kv_heads ร— head_dim โ€” the model's architecture. Note n_kv_heads, not attention heads โ€” this is where GQA saves memory (below).
  • bytes_per_value โ€” 2 for FP16 cache, 1 for Q8, ~0.5 for Q4. This is the quantization lever.
  • batch โ€” number of simultaneous requests. Each concurrent user needs a full separate cache โ€” this is the term everyone forgets.

A worked example: Llama 3.3 70B

Llama 3.3 70B has 80 layers, 8 KV heads (it uses grouped-query attention) and a head dimension of 128. For a single request at FP16 cache:

per token = 2 ร— 80 ร— 8 ร— 128 ร— 2 bytes = 327,680 bytes โ‰ˆ 0.31 MB 8K context โ†’ ~2.5 GB 32K context โ†’ ~10 GB 128K context โ†’ ~40 GB โ† as big as the Q4 weights!

That last line is the whole point. The Q4 weights are ~40GB; at full 128K context the cache doubles your memory need to ~80GB. This is why our VRAM guide insists you size for weights plus cache โ€” and why "it fits" from a weights-only calculator is a trap. Now multiply by concurrency: ten simultaneous users at 32K context each need ten caches โ€” ~100GB of cache alone.

Why GQA changed everything (and old formulas lie)

Older KV-cache formulas use the number of attention heads. Modern models use grouped-query attention (GQA), where many query heads share a small number of key/value heads โ€” Llama 70B has 64 query heads but only 8 KV heads. Since the cache stores KV heads, GQA cuts cache size by that ratio (8ร— here). A pre-GQA formula would predict eight times the memory and scare you off a model that actually fits. Always use n_kv_heads, which you'll find in the model's config.json as num_key_value_heads.

The two levers that make long context affordable

1. Cache quantization. The cache doesn't have to be FP16. Storing it at Q8 (1 byte/value) halves cache memory; Q4 quarters it. In Ollama, enable it with the OLLAMA_KV_CACHE_TYPE=q8_0 environment variable; in llama.cpp use --cache-type-k/--cache-type-v; vLLM and SGLang have FP8 cache options. Q8 cache is nearly lossless in practice and is the single highest-leverage setting for long-context local work โ€” it turns our 128K Llama example from ~40GB of cache into ~20GB.

2. Right-size the window. A model advertising 256K context does not force you to allocate 256K. Set the context to your real need: a chat assistant rarely uses more than 8โ€“16K; a document-RAG system sized to its chunk budget might need 32K, not 256K. In Ollama this is num_ctx; in vLLM, --max-model-len. Allocating headroom you never use is pure wasted VRAM โ€” the flip side of the "raise num_ctx" advice in our coding-assistant and Qwen3-Coder pages, where the mistake runs the other way.

The practical checklist

  • Budget VRAM as weights + KV-cache + ~1โ€“2GB overhead โ€” never weights alone.
  • Compute the cache at YOUR context and YOUR concurrency, not the model's maximum.
  • Turn on Q8 cache first โ€” it's nearly free quality-wise and buys the most room.
  • For serving, remember each concurrent request multiplies the cache โ€” this is what caps your user count, not the weights.
  • Prefer GQA models (virtually all current ones) and read num_key_value_heads from config.json for exact math.