A standard ZIP archive whose members are .npy files named "<key>.npy". np.savez stores them uncompressed (ZIP_STORED) and np.savez_compressed deflates them (ZIP_DEFLATED). Several named arrays, no metadata beyond names. Used by JAX/Flax tooling, scientific code, and older Keras/Chainer weight files.
.npz
What it is
many tensors
Byte order
per array declared
Dimension order
per array flag
Compression
optional
Metadata
none
Loading
Loading it into a library can execute code, depending on the loader and the file.
Versions
members
No archive-level format version. Each member is an npy 1.0, 2.0, or 3.0 file, including the NumPy 1.14 alignment change (64-byte data start; older members may be 16-byte aligned). ZIP64 is the APPNOTE mechanism numpy uses when a member or the archive exceeds the 4 GiB ZIP limits; this spec does not restate the ZIP64 extra field.
How to read it
np.savez writes a ZIP archive of STORED .npy members (np.savez_compressed uses deflate instead). Each member is a local file header, then the member name, then that member's npy file. After every member, the central directory lists those members again, and the end-of-central-directory record ends the file. Array bytes live only in the members. ZIP64 extra fields are not restated here; see the versions note and APPNOTE.
member = key + '.npy'. Positional arrays get keys arr_0, arr_1, ...; a positional array cannot be combined with a kwarg named arr_N. np.load strips a trailing '.npy' from the listed names and also keeps the raw member name. A member is parsed as .npy only when it starts with the npy magic; otherwise np.load returns that member's raw bytes and does not fail.
compression: none (savez) or deflate (savez_compressed); any ZIP method in principle. mmap: ZIP magic PK\x03\x04 or PK\x05\x06 makes np.load return a lazy NpzFile and does not pass mmap_mode through. A member is read, and a deflated member is inflated, only when that member is accessed. allow_pickle (default false) and max_header_size (default 10000) apply to each .npy member on its own; allow_pickle true lifts the header cap. A deflated member cannot be memory-mapped. data_offset below is the STORED case of that limit. A custom reader CAN mmap STORED members by computing the data offset (local header offset + 30 + name_len + extra_len + npy header length), but member data is not aligned (first member's array bytes were at offset 183 in a test file). sparse via-convention: scipy.sparse.save_npz writes data/indices/indptr/shape/format members.
local_file_header
bytes. APPNOTE local file header. Magic 50 4b 03 04. savez sets compression method 0 (stored).
member_name
utf8. Name length comes from the local header. np.savez uses '<key>.npy'.
npy_member
bytes. One formats/npy.yaml file, including its own preamble. This is the array payload.
central_directory
bytes. Central-directory headers, then the end-of-central-directory record. Not a second copy of the npy bytes.
member 0 member 1 tail
+--------+------+--------+ +--------+------+--------+ +----------+------+
| local | name | npy | ... | local | name | npy | | central | EOCD |
| header | .npy | file | | header | .npy | file | | directory| |
+--------+------+--------+ +--------+------+--------+ +----------+------+
One tensor
name
member filename with the '.npy' suffix removed
dtype
member npy header descr
shape
member npy header shape
data_offset
STORED only: local_header_offset + 30 + n + m + npy_preamble_and_header (n/m = name/extra lengths from the LOCAL header, which can differ from the central directory)
nbytes
prod(shape)*itemsize
alignment
1. no alignment of members
Reader
The procedure that finds each tensor's bytes.
read
pseudo-python
def read_npz(path, allow_pickle=False, max_header_size=10000):
z = ZipFile(path); out = []
for info in z.infolist():
key = info.filename[:-4] if info.filename.endswith(".npy") else info.filename
with z.open(info) as m: # inflated here, only when accessed
magic = m.read(6); m.seek(0)
if magic == b"\x93NUMPY":
t = read_npy(m, allow_pickle=allow_pickle, max_header_size=max_header_size)
t.name = key; out.append(t)
else:
out.append(Blob(name=key, data=m.read())) # not an array; do not fail
return {}, out
Reject the file when
Listed in the spec's order. Only rules marked MUST that reject the file are shown. The other IDs are warnings or implementation limits.
NPZ-001. valid ZIP (central directory found)
NPZ-002. each member intended as an array is a valid .npy (see npy.yaml)
Example
Example file. A ZIP archive of npy files, one member per array, named <key>.npy.
small.npz2,314 bytes
Name
Dtype
Shape
Bytes
w_f32
<f4float32
4 × 64
1,024
b_f16
<f2float16
8
16
e_bf16The header only says 2 opaque bytes. expected.json records this array as bfloat16.