Keras does not publish a separate format document; this page follows its saving
code: keras/src/saving/saving_lib.py
for .keras files, and
legacy_h5_format.py
with legacy/saving/saving_utils.py for the older .h5 model
files, all read 2026-11-12.
.keras archive
A .keras file is a ZIP archive with
these entries. The same files can also be written to a folder unzipped.
| Entry | Holds |
|---|---|
metadata.json | A JSON object with keras_version and date_saved, the local time in the form %Y-%m-%d@%H:%M:%S. |
config.json | The model as JSON, made by serialize_keras_object: records of the model, its layers and other saveables’ configuration, each with keys such as class_name, module and config. |
model.weights.h5 | The state of every saveable (layers, optimiser, loss and metrics), in HDF5. |
assets/ | Files a saveable writes as assets, for state that is not variables. |
Saveables are found through the model’s attributes, including lists, tuples and
dictionaries held in attributes. In model.weights.h5, each saveable’s
path is an HDF5 group holding a vars group; the variables are datasets
in it, and the model’s own variables are in a top-level vars group.
A bfloat16 variable is stored with a dtype attribute of
bfloat16.
When loading, Keras checks the sizes of ZIP members against expansion limits as a guard against ZIP bombs.
Legacy .h5 model
Before .keras, a whole model was one HDF5 file:
| Where | Name | Holds |
|---|---|---|
| Root attributes | keras_version | The Keras version. |
backend | The backend name. | |
model_config | JSON: {"class_name": …, "config": …}, the model’s class and get_config(). | |
training_config | JSON compile settings and optimiser configuration, when the model was compiled and saved with its optimiser. | |
Group model_weights | Attributes | layer_names, backend, keras_version. |
| One group per layer | Named after the layer (in name order), with a weight_names attribute and one dataset per weight, named by the weight’s path. | |
top_level_model_weights | The model’s own variables, laid out the same way. | |
Group optimizer_weights | – | The optimiser’s variables, when the optimiser is included. |
HDF5 cannot hold attributes larger than 64,512 bytes in an object header, so a
long list attribute such as layer_names or weight_names is
split into numbered attributes: layer_names0,
layer_names1 and so on.