Concepts¶
This page explains the data model behind a .stards file so the rest of the API
makes sense.
The .stards file¶
A StarDS dataset is a single .stards file that contains:
- a header with a magic string, format version, and an index of every entry;
- an array section holding (optionally compressed) N-dimensional array data;
- a metadata block holding small scalars and strings for fast access;
- optional per-layer metadata blocks for layered datasets.
For the exact byte layout, see the Format Specification.
Arrays¶
Arrays are typed, N-dimensional, and stored under the array namespace via
ds["key"] (Python) or store.put(key, ndarray) (C++). Supported element types:
- signed integers:
int8,int16,int32,int64 - unsigned integers:
uint8,uint16,uint32,uint64 - floating point:
float32,float64 string
Arrays are the right home for anything large or anything you want to
slice. In Python they round-trip with NumPy; the array
namespace requires an actual array (a raw Python scalar raises an error — wrap it
as np.array(5) or [5]).
Metadata¶
Metadata lives in a separate metadata namespace via ds.meta["key"] (Python)
or store.meta.put(key, value) (C++). It's intended for scalars, short strings,
and configuration — small values grouped into a compressed metadata block for
quick access. Unlike the array namespace, metadata accepts raw Python scalars and
strings directly.
Namespace separation¶
Arrays and metadata are independent namespaces, so the same key can exist in both without conflict:
| Namespace | Python | C++ | Best for |
|---|---|---|---|
| Array | ds["key"] |
store.put(key, arr) |
Large / numeric / sliceable data |
| Metadata | ds.meta["key"] |
store.meta.put(key, v) |
Scalars, strings, config |
Layers¶
Layers store multiple versions of the same logical data in one file. Each layer has isolated storage and opt-in inheritance from the base:
- Setting a key in a layer overrides it for that layer only — it never overwrites the base or other layers.
- Accessing a key that a layer did not set falls back to the base layer
only when inheritance is enabled. Inheritance is off by default; without
it, a missing key raises. Enable it with
ds.set_layer_inheritance(True)(or at open time viaOpenOptions).
With inheritance on you only store what changes in each layer; everything else is inherited. Layers apply to both arrays and metadata.
ds["cube"] = raw_cube
ds["wavelengths"] = np.linspace(400, 2500, 300)
processed = ds.create_layer("processed")
processed["cube"] = corrected_cube # override
# "wavelengths" not set → inherited from base when inheritance is on
ds.set_layer_inheritance(True) # off by default
layer = ds.get_layer("processed")
layer["cube"] # processed data
layer["wavelengths"] # inherited base wavelengths
Common uses: hyperspectral pipelines (raw → corrected → subset), multi-temporal datasets, A/B experiments, and dataset version control. See the Layers guide.
Compression¶
Array and metadata blocks can be compressed independently with GZIP,
LZ4, or none. Compression is block-based, so large arrays can be seeked
into without decompressing the whole thing. Configure it through StarConfig;
see the Compression guide.
Cloud storage¶
A .stards file can live locally or in the cloud. Use an s3:// URI (or the
/vsis3/ prefix) for S3, or an https:// URL (or /vsicurl/) for HTTP, and the
same API reads and (for S3) writes remotely.
See the Cloud Storage guide.