This page follows the format description in NumPy’s source,
numpy/lib/_format_impl.py
(the numpy.lib.format documentation), with type codes from the
array
interface and datetime pages and .npz details from
_npyio_impl.py, all read 2026-11-12. The format grew out of NumPy
Enhancement Proposal 1; the source says it is now more current than the NEP.
Layout
| Offset | Size | Field |
|---|---|---|
0 | 6 | Magic 93 4E 55 4D 50 59: the byte 93 and NUMPY. |
6 | 1 | Major version: 1, 2 or 3. |
7 | 1 | Minor version: 0. |
8 | 2 or 4 | Header length, little-endian: 2 bytes in version 1.0, 4 bytes in 2.0 and 3.0. |
10 or 12 | header length | The header text. |
| … | … | The array data. |
| Version | Difference |
|---|---|
| 1.0 | Header length is 2 bytes (at most 65,535); header text is ASCII (Latin-1). |
| 2.0 | Header length is 4 bytes, for headers too long for 1.0, such as structured types with many fields. |
| 3.0 | As 2.0, but the header text is UTF-8, so field names can use any characters. |
NumPy writes 1.0 when the header fits, then 2.0, then 3.0 if the header text needs characters outside Latin-1, and warns when it uses 2.0 or 3.0.
Header
The text of a Python dictionary literal, readable with
ast.literal_eval, with exactly these keys. Writers should sort the
keys alphabetically; readers must not depend on it.
| Key | Value |
|---|---|
'descr' | The element type: a type string (see type codes) or, for a structured array, a list of (name, type) or (name, type, shape) tuples. |
'fortran_order' | True: data is stored column-major (first index fastest). False: row-major (C order). |
'shape' | A tuple of dimensions, such as (3, 4); () for a single value; (5,) for one dimension. |
The header is padded with spaces and ends with a line feed, so that the total of magic, versions, length field and header is a multiple of 64 bytes. The data then starts aligned, which allows memory-mapping. NumPy also adds spare spaces after the dictionary so the length of the first (or, in Fortran order, last) dimension can be rewritten in place when an array grows.
93 4E 55 4D 50 59 01 00 76 00
{'descr': '<f8', 'fortran_order': False, 'shape': (3, 4), } …spaces… \n
Here the header is 0x76 = 118 bytes, so the data starts at byte 128.
Type codes
A type string is a byte-order character, a kind character and a size in bytes:
<f8 is a little-endian 8-byte float.
| Character | Meaning |
|---|---|
<, > | Little-endian, big-endian. |
| | Byte order is not relevant. |
b | Boolean, 1 byte per element. |
i, u | Signed and unsigned integers. |
f | Floating point. |
c | Complex floating point. |
m, M | Timedelta and datetime, with a unit: <M8[ns], <m8[s]. Units: Y, M, W, D, h, m, s, ms, us, ns, ps, fs, as. |
S | A fixed-length sequence of bytes (char): |S10. |
U | Unicode text of fixed length, in UCS-4 characters: <U10 is 40 bytes. |
V | Raw bytes (void): |V16. |
O | Python objects: the data is a pickle of the array, not raw values. NumPy refuses to load it unless allow_pickle=True, because a pickle can run code. |
.npz archives
numpy.savez writes several arrays into one ZIP
file, each as a .npy member named after its keyword (or
arr_0, arr_1…). savez_compressed uses Deflate;
savez stores them uncompressed.