What Is a .NPY File?
Numpy Array
NumPy Array File (.npy)
Overview
The .npy format is NumPy's native binary format for storing a single array on disk. It preserves everything the in-memory array knows about itself - the exact dtype, the shape, and the memory ordering - so a saved array reloads as an exact bitwise copy, with no parsing, no type inference, and no precision loss.
That is the key difference from CSV: writing a float64 array to CSV converts every value to text and back, which is slow and can lose the last bits of precision. An .npy file is essentially the raw memory buffer with a small self-describing header in front of it.
Technical Specifications
Format Details
- MIME Type:
application/octet-stream - File Extension:
.npy - Category: Data
- Specification: NEP 1 (NumPy Enhancement Proposal 1)
- Magic bytes:
93 4E 55 4D 50 59(\x93NUMPY) - Format versions: 1.0, 2.0 (longer headers), 3.0 (UTF-8 field names)
- Contains: exactly one array
Magic Number
00000000 93 4e 55 4d 50 59 01 00 76 00 7b 27 64 65 73 63 |.NUMPY..v.{'desc|
00000010 72 27 3a 20 27 3c 66 38 27 2c 20 27 66 6f 72 74 |r': '<f8', 'fort|
00000020 72 61 6e 5f 6f 72 64 65 72 27 3a 20 46 61 6c 73 |ran_order': Fals|
The leading \x93 is deliberately a non-ASCII byte, so the file cannot be mistaken for text. It is followed by the ASCII string NUMPY.
File Structure
An .npy file has three parts:
1. Magic string and version
\x93NUMPY + major (1 byte) + minor (1 byte)
2. Header
header length (2 bytes in v1.0, 4 bytes in v2.0+, little-endian)
header data (an ASCII/UTF-8 Python dict literal)
3. Raw array data
the array bytes, contiguous, in the declared order
The header dictionary always contains three keys:
{'descr': '<f8', 'fortran_order': False, 'shape': (1000, 3)}
descr: a dtype string.<means little-endian,f8means 8-byte float. So<f8is float64.fortran_order:Falsefor C-contiguous (row-major),Truefor Fortran-contiguous (column-major).shape: the array dimensions as a tuple.
The header is padded with spaces so that the data section begins on a 64-byte boundary, which lets NumPy memory-map the file directly.
History and Development
Before .npy, NumPy users saved arrays either as text (losing speed and precision) or with Python's pickle (tying the file to Python and creating a security hazard). NEP 1, accepted in 2007, defined a minimal binary format that was language-neutral, self-describing, and simple enough to reimplement in a few dozen lines.
Version 2.0 raised the header size limit for arrays with very many structured fields, and version 3.0 allowed UTF-8 in structured dtype field names. The format has otherwise been stable for well over a decade, which is a large part of its value.
Common Use Cases
- Intermediate results: caching an expensive computation so a pipeline can resume without recomputing.
- Machine learning datasets: storing feature matrices, embeddings, and label vectors.
- Scientific data exchange: passing arrays between Python, Julia, R, and C++ tools.
- Memory-mapped access: reading slices of an array larger than RAM without loading the whole file.
- Test fixtures: pinning exact numeric inputs and expected outputs for regression tests.
How to Open an NPY File
In Python
import numpy as np
# Load the whole array
arr = np.load("data.npy")
print(arr.shape, arr.dtype)
# Memory-map instead of reading it all into RAM
big = np.load("huge.npy", mmap_mode="r")
chunk = big[1000:2000] # only this slice is read from disk
Saving
import numpy as np
arr = np.random.rand(1000, 3)
np.save("data.npy", arr) # .npy is appended automatically
Inspecting without loading the data
import numpy as np
with open("data.npy", "rb") as f:
version = np.lib.format.read_magic(f)
shape, fortran_order, dtype = np.lib.format.read_array_header_1_0(f)
print(shape, dtype, "fortran" if fortran_order else "c-order")
From the shell
# The header is human-readable ASCII in the first ~100 bytes
head -c 128 data.npy | xxd
file data.npy
In other languages
- Julia:
NPZ.jl - R: the
RcppCNPypackage - C++:
cnpy, orxtensor-io - Rust: the
ndarray-npycrate - Go:
github.com/sbinet/npyio
Security Considerations
np.load accepts an allow_pickle argument. When it is True, loading a file containing an object-dtype array executes pickle deserialisation, which can run arbitrary code. NumPy changed the default to False in version 1.16.3 precisely because of this risk.
Never set allow_pickle=True for a file you did not create yourself. A plain numeric .npy file never needs it.
Advantages
- Exact round-trip: dtype, shape, and byte order are preserved perfectly.
- Fast: essentially a memory copy; no parsing.
- Self-describing: the file states its own type and shape.
- Memory-mappable: the aligned header allows lazy, partial reads of huge arrays.
- Simple: the specification is short enough to implement from scratch.
Limitations
- One array per file: use NPZ for multiple arrays.
- No compression: the data section is stored raw.
- Not human-readable: only the header is text.
- Weak ecosystem outside Python: support exists elsewhere but is rarely built in.
- No schema evolution: the file records a fixed dtype with no versioning of your own data model.
Related Formats
- NPZ: a ZIP archive holding several
.npyfiles. - PICKLE: Python's general object serialisation, more flexible but unsafe to load from untrusted sources.
- PARQUET: columnar storage for tabular data, with compression and a real schema.
- H5: HDF5, for large hierarchical scientific datasets.
- CSV: the text alternative: portable and readable, but slow and lossy for floats.
File Information
Numpy Array
Data
.npy
application/octet-stream
Related File Types
Other file types in the Data category you might also need:
Start Analyzing NPY Files Now
Use our free AI-powered tool to detect and analyze Numpy Array files instantly with Google's Magika technology.
⚡Try File Detection Tool