Model file formats
A model release is not one file โ it's a checkpoint that gets repackaged per engine. This page maps the formats you'll actually meet locally: GGUF for the llama.cpp world, safetensors for the PyTorch/HF stack, engine-native GPU quants, and ONNX for edge runtimes. Pick the engine first; the format follows.
GGUF: one file, everything in it
A .gguf file packs model weights, tokenizer vocabulary, chat template, and per-tensor metadata into a single binary. One download, zero configuration, and every GGUF-speaking app runs the same file: llama.cpp and llama-server, Ollama, LM Studio, Jan, KoboldCpp. The format is memory-mappable, so weights stream from disk page by page โ startup is fast and the OS page cache does the caching for free.
Filename anatomy, field by field, for Qwen3-8B-Q4_K_M.gguf:
| Field | Value | Meaning |
|---|---|---|
Qwen3 |
family + generation | the architecture the engine builds; also the quality generation |
8B |
size class | ~8 billion parameters โ the number your VRAM budget keys off |
Q4_K_M |
quant tag | ~4.8 bits per weight, K-quant "medium" mix โ see quantization |
.gguf |
container | weights + tokenizer + chat template + metadata, one file |
Inspect any GGUF without loading it:
python gguf-py/gguf/scripts/gguf_dump.py model.gguf
general.architecture : qwen3
general.name : Qwen3 8B
qwen3.context_length : 32768
tokenizer.ggml.model : gpt2 (BPE)
tokenizer.chat_template : {%- ... a Jinja template ... %}
That metadata block is why a GGUF "just works" across five different apps: the engine reads the architecture, builds the graph, loads the tokenizer, and chat front-ends apply the embedded template. No config hunting, no vocab mismatch, no separate tokenizer download.
Safetensors: the Hugging Face native
Safetensors is a deliberately boring container: a JSON header of tensor names, shapes, and dtypes followed by raw bytes. It stores only tensors โ no executable code, unlike pickle-flavored .bin checkpoints that are unsafe to load blindly โ and it supports zero-copy mmap, which is why PyTorch startup is fast. Transformers, vLLM, SGLang, TRL, and the whole fine-tuning ecosystem speak it natively.
Because it stores only tensors, a working model is the whole repo directory:
model-00001-of-00004.safetensors โ weight shards (~5 GB each)
model-00002-of-00004.safetensors
model-00003-of-00004.safetensors
model-00004-of-00004.safetensors
model.safetensors.index.json โ shard map: tensor name โ shard file
config.json โ architecture + hyperparameters
generation_config.json โ default sampling settings
tokenizer.json โ the tokenizer itself
tokenizer_config.json โ chat template lives here
Sharding exists because a 70B FP16 checkpoint is ~140 GB โ one file would be unmanageable. If you serve with vLLM you download all shards; there is no "just the 4-bit file" shortcut inside a safetensors release. Quantized serving is a separate repo (an AWQ or GPTQ variant of the same model).
Engine-native GPU quants: AWQ, GPTQ, EXL2
These formats exist for GPU inference servers, where throughput matters more than file convenience:
- AWQ โ activation-aware quantization. Calibration prompts find the ~1% of weight channels that activations depend on most; those get protected scaling, everything else goes to 4-bit. Near-original quality at 4-bit with fast kernels; the default 4-bit choice in vLLM.
- GPTQ โ the classic GPU quant, descended from optimal brain quantization: quantize layer by layer, compensating each layer's error against the not-yet-quantized weights. 4-bit, GPU-only kernels, still everywhere in serving configs.
- EXL2 โ exllamav2's format with variable bits per weight. One repo can sit at, say, 4.65 bpw by mixing 2โ8 bit tensors so the total lands exactly under your VRAM cap. The tool for when Q4 doesn't fit but Q3 would hurt.
All three require calibration data and a one-time conversion run, and none of them run on CPU.
ONNX, MLX, raw FP16/BF16
ONNX is the portable compute-graph format: export a transformers model once, run it anywhere onnxruntime runs โ Windows boxes without CUDA, phones, browser WebGPU demos. onnxruntime can also quantize the graph to INT8 for CPU. You pay setup friction and often peak speed; you gain portability to machines with no PyTorch stack. Edge and embedded are its home turf, not desktop chat.
MLX is Apple's array framework for Apple Silicon; the mlx-community org repacks most major releases into MLX format, 4-bit and 8-bit included. On an M-series Mac running mlx-lm, that's your format โ see Apple Silicon.
Raw FP16/BF16 checkpoints matter when you want a lossless reference, a fine-tuning base, or a conversion source. BF16 keeps FP32's 8-bit exponent range and trades mantissa bits for it โ far more stable for training than FP16, at the same 2 bytes per weight. A 7โ8B model at FP16/BF16 is ~16 GB of weights alone, before any context.
Which format for which engine
| Engine / stack | Format it eats | Notes |
|---|---|---|
| llama.cpp, Ollama, LM Studio, Jan | GGUF | one file; CPU + GPU; every quant family |
| vLLM, TGI, SGLang | safetensors, AWQ, GPTQ | server throughput; GPU |
| exllamav2 / TabbyAPI | EXL2, GPTQ | variable bpw; GPU |
| transformers / PyTorch | safetensors | training, fine-tuning, research |
| onnxruntime | ONNX | edge, mobile, browser |
| mlx-lm | MLX | Apple Silicon |
Mixing formats is the classic beginner mistake: pointing vLLM at a .gguf, or llama.cpp at safetensors shards. Neither works โ the engine either errors out or needs a conversion step first.
Conversion paths
The standard path from a Hugging Face repo to a local file is two steps โ convert the checkpoint to a 16-bit GGUF, then quantize down:
git clone https://github.com/ggerganov/llama.cpp
pip install -r llama.cpp/requirements.txt
# 1. convert the HF checkpoint (safetensors) to GGUF
python llama.cpp/convert_hf_to_gguf.py ./Qwen3-8B --outtype bf16 --outfile qwen3-8b-bf16.gguf
# 2. quantize to the target size
llama-quantize qwen3-8b-bf16.gguf qwen3-8b-Q4_K_M.gguf Q4_K_M
In practice you rarely convert yourself: quantizers like bartowski and mradermacher publish every size of every notable release within hours. Convert on your own when you have a private fine-tune, want an imatrix-calibrated I-quant, or need a nonstandard bit target โ details in quantization.
Embedding models โ the retrieval half of RAG โ ship in the same formats: GGUF for llama.cpp's embedding endpoint, safetensors for sentence-transformers. Same rule as everything above: match the format to the engine you'll actually run.
Related: Quantization ยท Model families ยท Engines ยท RAG