- Safetensors is a file format for storing machine learning model weights that prevents arbitrary code execution vulnerabilities present in pickle-based formats
- It loads 2-10× faster than PyTorch .bin files with zero-copy memory mapping and supports lazy loading for multi-GB models
- Install with
pip install safetensorsand usesafe_open()to load orsave_file()to save tensors - Widely supported by Hugging Face, Ollama, LM Studio, ComfyUI, and all major ML frameworks
Safetensors is a binary file format for storing and loading machine learning model weights developed by Hugging Face. It addresses critical security vulnerabilities in pickle-based formats (PyTorch .bin, .pt files) by using a simple, statically parseable structure that cannot execute arbitrary code during deserialization. The format achieves significantly faster load times through memory mapping and zero-copy operations, making it the preferred format for distributing and loading AI models in 2026.
What Is Safetensors
Safetensors stores tensors (multi-dimensional arrays of numbers that represent neural network weights) in a plain binary format with a JSON header. Unlike pickle-based formats used historically in PyTorch, safetensors contains only raw tensor data and metadata—no Python code, no class definitions, no executable instructions.
The file structure consists of:
- An 8-byte header containing the metadata length
- A JSON metadata section describing tensor names, shapes, data types, and byte offsets
- Raw tensor data stored contiguously in memory-aligned blocks
This simplicity enables memory-mapped loading: the operating system maps the file directly into process memory, allowing instant access to tensor data without copying gigabytes into RAM. When you open a 7B parameter model stored as safetensors, the load time is measured in milliseconds rather than seconds.
Why Safetensors Was Created
The Python pickle format, used by default in PyTorch’s torch.save() and torch.load(), can execute arbitrary Python code during deserialization. A malicious actor can craft a .bin or .pt file that runs malware when you call torch.load(). This is not a theoretical vulnerability—multiple incidents have demonstrated weaponized model files in the wild.
Beyond security, pickle-based formats suffer from performance issues:
| Issue | Pickle-based (.bin, .pt) | Safetensors |
|---|---|---|
| Arbitrary code execution | Yes, inherent to pickle | No, static format |
| Load time for 7B model | 5-15 seconds | 0.5-2 seconds |
| Memory overhead during load | 2× model size (copy required) | ~1× (memory mapping) |
| Framework portability | Python/PyTorch specific | Any language with bindings |
| Lazy loading support | No | Yes |
When loading a pickle file, Python must deserialize the entire structure into memory, reconstruct Python objects, then copy tensor data into the framework’s native format. Safetensors eliminates these steps by directly mapping the binary tensor data.
Installing and Using Safetensors
Install the Python library:
pip install safetensorsLoading Safetensors Files
Use safe_open() for memory-mapped lazy loading:
from safetensors import safe_open
with safe_open("model.safetensors", framework="pt", device="cpu") as f:
# Get list of tensor names
tensor_names = f.keys()
# Load specific tensor (lazy - only loads this tensor)
embedding_weights = f.get_tensor("model.embed_tokens.weight")
# Get tensor metadata without loading
metadata = f.metadata()The framework parameter specifies the target framework: "pt" for PyTorch, "tf" for TensorFlow, "np" for NumPy, or "jax" for JAX. The device parameter controls where tensors are placed: "cpu", "cuda:0", or other device identifiers.
To load all tensors at once:
from safetensors.torch import load_file
tensors = load_file("model.safetensors")
# Returns dict: {"layer.weight": tensor, "layer.bias": tensor, ...}Saving Safetensors Files
Save a dictionary of tensors:
from safetensors.torch import save_file
import torch
tensors = {
"embedding.weight": torch.randn(50000, 768),
"layer1.weight": torch.randn(768, 768),
"layer1.bias": torch.randn(768)
}
save_file(tensors, "model.safetensors")Include custom metadata:
save_file(
tensors,
"model.safetensors",
metadata={"model_type": "bert", "vocab_size": "50000"}
)Loading Models from Hugging Face
Hugging Face’s transformers library uses safetensors automatically when available:
from transformers import AutoModel
# Automatically downloads and loads .safetensors if available
model = AutoModel.from_pretrained("bert-base-uncased")Force safetensors format:
model = AutoModel.from_pretrained(
"bert-base-uncased",
use_safetensors=True # Fail if safetensors not available
)Most models on Hugging Face Hub now include both model.safetensors and pytorch_model.bin files. The library prefers safetensors when both exist.
Converting Between Formats
PyTorch .bin to Safetensors
from safetensors.torch import save_file
import torch
# Load PyTorch checkpoint
state_dict = torch.load("pytorch_model.bin", map_location="cpu")
# Save as safetensors
save_file(state_dict, "model.safetensors")Safetensors to PyTorch .bin
from safetensors.torch import load_file
import torch
tensors = load_file("model.safetensors")
torch.save(tensors, "pytorch_model.bin")Hugging Face Conversion Script
The transformers library includes a conversion tool:
python -m transformers.convert_safetensors_to_pytorch
--model_name_or_path ./model_folder
--output_dir ./convertedFile Format Technical Details
A safetensors file has this structure:
- Header (8 bytes): Little-endian unsigned 64-bit integer containing the JSON metadata length in bytes
- Metadata (variable): JSON object with this schema:
{ "layer_name": { "dtype": "F32", // Data type: F32, F16, BF16, I64, I32, etc. "shape": [768, 768], // Tensor dimensions "data_offsets": [0, 2359296] // Start and end byte in data section }, "__metadata__": { // Optional custom metadata "key": "value" } } - Data section: Raw tensor bytes, stored in C-contiguous order (row-major), aligned to 8-byte boundaries
The format supports these data types: F64, F32, F16, BF16, I64, U64, I32, U32, I16, U16, I8, U8, BOOL. Each tensor’s byte range is specified in the metadata, enabling selective loading without parsing the entire file.
Ecosystem Support
Safetensors is supported across the AI ecosystem:
| Tool/Framework | Support Level | Notes |
|---|---|---|
| Hugging Face Transformers | Native | Default format since v4.30 |
| Hugging Face Diffusers | Native | Used for Stable Diffusion models |
| PyTorch | Via library | Requires safetensors package |
| TensorFlow | Via library | Supported through bindings |
| JAX | Via library | Supported through bindings |
| Ollama | Native | Converts to GGUF internally |
| LM Studio | Native | Loads safetensors directly |
| ComfyUI | Native | Primary format for custom models |
| AUTOMATIC1111 | Native | Stable Diffusion WebUI support |
| llama.cpp | Via conversion | Convert to GGUF format |
| vLLM | Native | Inference server support |
| TGI | Native | Text Generation Inference support |
When evaluating whether a model will fit in your GPU memory, use the VRAM calculator to estimate requirements based on parameter count and quantization level. The file format itself does not affect VRAM usage—safetensors and pickle files of the same model consume identical GPU memory once loaded.
Performance Characteristics
Benchmarks on a system with NVMe SSD and 64GB RAM loading a 7B parameter model:
| Format | Load Time | Peak RAM Usage | File Size |
|---|---|---|---|
| PyTorch .bin | 8.2s | 28GB | 13.5GB |
| Safetensors (load_file) | 1.1s | 14GB | 13.5GB |
| Safetensors (safe_open lazy) | 0.08s | 0.5GB | 13.5GB |
The lazy loading approach with safe_open() is particularly valuable when you need to inspect model architecture, extract specific layers, or load models that exceed available RAM by loading tensors selectively.
For quantized models, safetensors supports all standard data types including FP16, BF16, INT8, and INT4. The AI models database includes safetensors file sizes and VRAM requirements for 37 popular models across different quantization levels.
Sharded Models
Models larger than a few gigabytes are often distributed as multiple safetensors files (sharding). A 70B parameter model might be split into 8 shards:
model-00001-of-00008.safetensors
model-00002-of-00008.safetensors
...
model-00008-of-00008.safetensors
model.safetensors.index.jsonThe index file maps tensor names to shard files:
{
"metadata": {"total_size": 141123453952},
"weight_map": {
"model.embed_tokens.weight": "model-00001-of-00008.safetensors",
"model.layers.0.self_attn.q_proj.weight": "model-00001-of-00008.safetensors",
"model.layers.40.mlp.gate_proj.weight": "model-00005-of-00008.safetensors"
}
}Hugging Face libraries handle sharded loading automatically. Manual loading:
import json
from safetensors import safe_open
with open("model.safetensors.index.json") as f:
index = json.load(f)
weight_map = index["weight_map"]
# Load specific tensor by looking up its shard
tensor_name = "model.layers.20.mlp.down_proj.weight"
shard_file = weight_map[tensor_name]
with safe_open(shard_file, framework="pt", device="cpu") as f:
tensor = f.get_tensor(tensor_name)Language Bindings
While the reference implementation is Python, safetensors has bindings for multiple languages:
- Rust: Core implementation in Rust for performance and safety
- Python: Official bindings via PyPI
- JavaScript/Node.js:
@huggingface/safetensorsnpm package - C/C++: Available through FFI to Rust library
- Go: Community implementations available
The Rust implementation is the canonical reference. The Python bindings wrap this implementation, inheriting its performance characteristics.
Frequently Asked Questions
Can I use safetensors with existing PyTorch models without code changes?
Yes, if you’re using Hugging Face libraries. For custom models, you need to change torch.load() to load_file() from safetensors and torch.save() to save_file(). The tensor data and model architecture remain identical—only the serialization format changes. Converting existing checkpoints is a one-time operation that takes seconds.
Do safetensors files work across different PyTorch versions?
Yes. Unlike pickle files, which can break across Python or PyTorch version changes, safetensors stores raw binary data without version-specific serialization. A safetensors file created with PyTorch 1.12 loads correctly in PyTorch 2.x, and vice versa. This makes safetensors superior for long-term model archival and distribution.
Why are some models on Hugging Face Hub still distributed as .bin files?
Older models uploaded before 2023 may only have pickle-based files. Hugging Face is gradually converting the model hub, but some models remain pickle-only if the original uploader has not provided safetensors versions. When both formats exist, safetensors is preferred automatically. You can convert locally using the method shown in the conversion section above.
Does safetensors increase file size compared to PyTorch .bin?
No. File sizes are typically identical or within 1-2% because both formats store the same raw tensor data. Safetensors adds minimal overhead (a JSON header of a few kilobytes), while pickle adds Python object serialization overhead. For a 7B model, both formats produce ~13-14GB files. The difference is load speed and security, not storage efficiency.
Can I inspect safetensors files without loading the full model into memory?
Yes, this is one of safetensors’ key advantages. Use safe_open() to read the metadata and selectively load specific tensors. You can list all tensor names, check their shapes and data types, and extract individual layers without loading the entire multi-gigabyte file. This is particularly useful for model analysis, debugging, and extracting components.
Are GGUF and safetensors the same thing?
No. GGUF (GPT-Generated Unified Format) is a different format used primarily by llama.cpp for quantized inference. GGUF includes quantization schemes optimized for CPU inference that safetensors does not support. Safetensors is designed for training and general-purpose model distribution, while GGUF is optimized for efficient inference on consumer hardware. Many tools like Ollama accept safetensors as input and convert to GGUF internally for inference.

