Containers · .gguf
GGUF (GGML Universal File)
Single-file, mmap-friendly container used by ggml / llama.cpp / whisper.cpp and derivatives. Fixed header, typed key/value metadata section, tensor-info table, zero-padding to an alignment boundary, then a tensor data blob. Tensors may use plain element types (F32/F16/BF16/I8..I64/F64) or ggml block-quantized types (Q4_0, Q8_0, K-quants, IQ-quants, TQ, MXFP4, NVFP4, Q1_0, Q2_0). Dimension order is ggml order: ne[0] is the innermost (fastest-varying, contiguous) dimension, i.e. the REVERSE of numpy/PyTorch shape order.
.gguf
- What it is
- many tensors
- Byte order
- undeclared default little
- Dimension order
- innermost first (ggml ne[])
- Compression
- none
- Metadata
- typed kv
- Loading
- Loading it into a library does not execute code.
How to read it
header (incl. all metadata KV) | tensor_info[tensor_count] | zero padding to ALIGNMENT (absolute file offset) | tensor_data. Every field is packed (no implicit alignment) except the padding before tensor_data and between tensors. ALIGNMENT is only known after parsing metadata (general.alignment).
- header
- gguf_header
- tensor_infos
- gguf_tensor_info[header.tensor_count]
- padding
- u8[align_up(pos, ALIGNMENT) - pos]. ggml only seeks to the aligned offset when tensor_count > 0
- tensor_data
- bytes. each tensor at data_start + info.offset; gap between tensors zero-padded to ALIGNMENT
0 4 8 16 24 +--------+--------+----------------+----------------+-----------------------------+ | "GGUF" | ver u32| tensor_cnt u64 | kv_count u64 | kv[0] kv[1] ... (packed) | +--------+--------+----------------+----------------+-----------------------------+ | tensor_info[0] ... tensor_info[n-1] (packed) | +----------------------------------------------------------------------------------+ | 0x00 padding up to multiple of ALIGNMENT (absolute file offset) | +----------------------------------------------------------------------------------+ <- data_start | tensor 0 data | pad | tensor 1 data | pad | ... | +----------------------------------------------------------------------------------+
One tensor
- name
- tensor_info.name (UTF-8)
- dtype
- tensor_info.type (ggml_type) -> dtypes[].canonical
- shape
- reversed(tensor_info.dimensions) # canonical row-major shape
- data_offset
- data_start + tensor_info.offset (absolute)
- nbytes
- see nbytes_formula
- order
- row-major (C) in canonical shape terms; no strides
Example
The specs test vector. Shapes are outermost first: the file stores that list reversed, fastest dimension first. w_q8_0 is the Q8_0 blocks for w_f32. e_bf16 is in this file. s_f32 is not: a scalar is stored as one dimension of length 1, and that stored shape must not replace the canonical shape [].
small.gguf1,792 bytes
- Version
- 3
- general.architecture
- llama
- test.answer
- 42
- test.note
- tensor-format-specs
| Name | Dtype | Shape | Stored order | Bytes |
|---|---|---|---|---|
| w_f32 | F32float32 | 4 × 64 | 64 × 4 | 1,024 |
| b_f16 | F16float16 | 8 | 8 | 16 |
| i_i32 | I32int32 | 3 × 2 | 2 × 3 | 24 |
| e_bf16 | BF16bfloat16 | 2 × 3 | 3 × 2 | 12 |
| w_q8_0 | Q8_0ggml_q8_0 | 4 × 64 | 64 × 4 | 272 |
Number formats
The name in the file, and the canonical dtype it maps to.
| In the file | Canonical | Bits |
|---|---|---|
| F32 | float32 | 32 |
| F16 | float16 | 16 |
| BF16 | bfloat16 | 16 |
| F64 | float64 | 64 |
| I8 | int8 | 8 |
| I16 | int16 | 16 |
| I32 | int32 | 32 |
| I64 | int64 | 64 |
| Q4_2 | none | — |
| Q4_3 | none | — |
| Q4_0_4_4 | none | — |
| Q4_0_4_8 | none | — |
| Q4_0_8_8 | none | — |
| IQ4_NL_4_4 | none | — |
| IQ4_NL_4_8 | none | — |
| IQ4_NL_8_8 | none | — |
Quantized block types (27)
| In the file | Canonical | Bits |
|---|---|---|
| Q4_0 | ggml_q4_0 | 4.5 |
| Q4_1 | ggml_q4_1 | 5 |
| Q5_0 | ggml_q5_0 | 5.5 |
| Q5_1 | ggml_q5_1 | 6 |
| Q8_0 | ggml_q8_0 | 8.5 |
| Q8_1 | ggml_q8_1 | 9 |
| Q2_K | ggml_q2_k | 2.625 |
| Q3_K | ggml_q3_k | 3.4375 |
| Q4_K | ggml_q4_k | 4.5 |
| Q5_K | ggml_q5_k | 5.5 |
| Q6_K | ggml_q6_k | 6.5625 |
| Q8_K | ggml_q8_k | 9.125 |
| IQ2_XXS | ggml_iq2_xxs | 2.0625 |
| IQ2_XS | ggml_iq2_xs | 2.3125 |
| IQ2_S | ggml_iq2_s | 2.5625 |
| IQ3_XXS | ggml_iq3_xxs | 3.0625 |
| IQ3_S | ggml_iq3_s | 3.4375 |
| IQ1_S | ggml_iq1_s | 1.5625 |
| IQ1_M | ggml_iq1_m | 1.75 |
| IQ4_NL | ggml_iq4_nl | 4.5 |
| IQ4_XS | ggml_iq4_xs | 4.25 |
| TQ1_0 | ggml_tq1_0 | 1.6875 |
| TQ2_0 | ggml_tq2_0 | 2.0625 |
| MXFP4 | ggml_mxfp4 | 4.25 |
| NVFP4 | ggml_nvfp4 | 4.5 |
| Q1_0 | ggml_q1_0 | 1.125 |
| Q2_0 | ggml_q2_0 | 2.25 |
Sources
- ggml docs/gguf.md (format specification)
- ggml include/ggml.h (enum ggml_type, enum ggml_ftype, GGML_MAX_DIMS, GGML_MAX_NAME)
- ggml src/ggml-common.h (block_* structs, QK_* constants, lookup tables)
- ggml src/ggml-quants.c (dequantize_row_* / quantize_row_*_ref)
- ggml src/ggml-impl.h (E8M0 / UE4M3 scale decoders)
- ggml src/gguf.cpp (reference reader/writer, validation behaviour)
- llama.cpp gguf-py/gguf/constants.py (Keys, GGMLQuantizationType, LlamaFileType, GGML_QUANT_SIZES)
- llama.cpp PRs that defined GGUF v1, widened it to v2, added big-endian v3, then dropped v1
- llama.cpp tools/gguf-split/gguf-split.cpp and llama_split_path