Skip to content

Object Store

natsio.objectstore.ObjectStore

ObjectStore(
    ctx: JetStreamContext, bucket: str, stream: Stream
)

A handle to one Object Store bucket.

Obtain via JetStreamContext.object_store() / JetStreamContext.create_object_store().

info async

info(
    name: str, *, show_deleted: bool = False
) -> ObjectInfo

The object's metadata. Raises ObjectNotFoundError for a missing object — or its subclass ObjectDeletedError when the latest revision is a delete marker.

With show_deleted=True a delete marker is returned instead of raising (deleted=True, size/chunks 0) — the same view list(include_deleted=True) and watch() see.

put async

put(meta: str | ObjectMeta, data: ObjectData) -> ObjectInfo

Store an object (replacing any existing object of that name).

data may be in-memory bytes or an async iterable of byte chunks — the input is re-chunked to meta.chunk_size (default 128KiB) and SHA-256 digested as it streams. If the put fails partway — including losing a concurrent same-name race — its already published chunks are purged (best effort) so nothing is orphaned; the revision it replaces stays intact either way. Returns the info of THIS revision, exactly as written.

delete async

delete(name: str) -> None

Replace the metadata with a delete marker and purge the chunks.

The marker keeps the object's name visible to watch() / list(include_deleted=True); the data is gone. The marker write is CAS-gated, so a delete racing a put deletes the put's revision (or the put lands after and legitimately recreates the object) — it can never report success while silently leaving the old data live.

update_meta async

update_meta(name: str, meta: ObjectMeta) -> ObjectInfo

Update an object's description, metadata, and headers in place.

The stored data is untouched: chunks, nuid, digest, size and the object's options (link, chunk size) carry over from the current revision — only meta's description / metadata / headers (and name, see below) are rewritten. meta.chunk_size is ignored here: it only governs how new data is split at put time and is meaningless for an in-place meta rewrite (nats.go likewise refuses to touch the options on UpdateMeta).

RENAME — when meta.name differs from name the object moves: the metadata is rewritten under the new name's subject and the old name's meta subject is purged, so info(name) then raises ObjectNotFoundError. The chunks stay under the same nuid (no data is copied). Renaming onto a live object raises ObjectExistsError; onto a deleted name is allowed (it overwrites the marker).

Raises ObjectNotFoundError if name never existed and ObjectDeletedError (its subclass) if the latest revision is a delete marker — a deleted object cannot be updated.

Every meta write is CAS-gated like put() / delete(). On a rename the new meta is written first and the old subject purged second (nats.go's order): a crash in that window leaves the object readable under both names — same nuid, same chunks — until a later write cleans it up; it is never data loss. A rename is NOT safe against a concurrent writer of the source name (the two names share one nuid, so a racing put/delete on either name affects the other — inherent to the ADR-20 format, same as nats.go).

get

get(
    name: str,
    *,
    chunk_timeout: float = 30.0,
    show_deleted: bool = False,
) -> ObjectResult

Stream an object's data with digest verification.

Follows one link hop transparently. chunk_timeout bounds the wait for each chunk and is always finite — a stream that lost chunks raises NoMessagesError instead of hanging forever (pass a larger value for very slow links, never None).

With show_deleted=True a deleted object resolves to its delete marker and yields no chunks (empty content, result.info is the marker) instead of raising — otherwise a delete marker raises ObjectDeletedError. The flag applies only to name itself; a link target is always resolved live (a dangling link still raises).

:

async with obj.get("report.pdf") as result:
    print(result.info.size)
    async for chunk in result:
        ...

get_bytes async

get_bytes(name: str) -> bytes

The whole object in one buffer (small objects, tests, scripts).

add_link(name: str, target: ObjectInfo) -> ObjectInfo

Store name as a link to target (an info from any bucket).

Links carry no data — get on the link streams the target. Refuses deleted targets and links-to-links; refuses to shadow an existing live non-link object (ObjectExistsError).

add_bucket_link(
    name: str, bucket: str | ObjectStore
) -> ObjectInfo

Store name as a link to a whole bucket (no object name).

Bucket links are directory-entry style pointers: get on one raises LinkError — open the linked bucket via JetStreamContext.object_store() instead.

watch

watch(
    *,
    updates_only: bool = False,
    ignore_deletes: bool = False,
) -> ObjectWatcher

Watch the bucket's metadata for changes.

Yields ObjectInfo items and exactly one None marker once the current state has been fully delivered (immediately for updates_only); afterwards it streams live updates. Self-healing — backed by the ordered consumer.

There is deliberately no include_history: every meta write rolls up its subject, so the stream only ever holds each object's latest revision — Object Store has no history surface (unlike KV).

list async

list(*, include_deleted: bool = False) -> list[ObjectInfo]

Every object in the bucket (links included; delete markers only with include_deleted). An empty bucket returns [] promptly.

seal async

seal() -> None

Make the bucket immutable: no further puts, deletes, or purges.

Do not seal while writers are in flight: a put interrupted by the seal can leave chunks that are then permanently unreclaimable (nothing can purge a sealed stream — server-enforced, probe-confirmed).

natsio.objectstore.ObjectResult

ObjectResult(
    store: ObjectStore,
    name: str,
    *,
    chunk_timeout: float,
    show_deleted: bool = False,
)

An active read: async context manager + async iterator of chunks.

info is the (link-resolved) metadata, available once iteration starts — or after __aenter__ when used as a context manager. The digest and size are verified after the final chunk; a mismatch raises DigestMismatchError, so a completed iteration is a verified read.

natsio.objectstore.ObjectStoreConfig dataclass

ObjectStoreConfig(
    *,
    bucket: str,
    description: str | None = None,
    ttl: timedelta | None = None,
    max_bytes: int = -1,
    storage: StorageType = StorageType.FILE,
    replicas: int = 1,
    placement: Placement | None = None,
    compression: bool = False,
    metadata: dict[str, str] | None = None,
)

Bucket configuration (maps onto an ADR-20 OBJ_<bucket> stream).

natsio.objectstore.ObjectMeta dataclass

ObjectMeta(
    *,
    name: str,
    description: str | None = None,
    metadata: dict[str, str] | None = None,
    headers: dict[str, list[str]] | None = None,
    chunk_size: int | None = None,
)

What the caller provides when storing an object.

natsio.objectstore.ObjectInfo dataclass

ObjectInfo(
    *,
    extra: dict[str, Any] = dict(),
    name: str = "",
    description: str | None = None,
    metadata: dict[str, str] | None = None,
    headers: dict[str, list[str]] | None = None,
    options: ObjectMetaOptions | None = None,
    bucket: str = "",
    nuid: str = "",
    size: int = 0,
    chunks: int = 0,
    digest: str | None = None,
    deleted: bool | None = None,
    mtime: Annotated[datetime | None, RFC3339] = None,
)

Bases: JsonModel

An object's stored metadata (the payload of its rollup meta message).

mtime is stamped from the meta message's stream timestamp on read — authoritative over anything found in the JSON.