Skip to content
qibdo qibdo
Theme
Book a demo

Buckets and objects

Storage uses a simple two-level model: workspace-scoped buckets that hold objects. This page explains what each one is and how it behaves. It stays conceptual; the API reference is where the exact fields, methods, and limits live.

A bucket is a container for objects. Every bucket belongs to one workspace and is provisioned on a cloud provider. It has a human-readable name that is unique within its workspace, an optional description, and a default storage class, a reference to one of the storage classes available to it.

On qibdo’s own engine, a bucket lives in a single region, chosen when you create it and fixed afterward, and supports versioning. With versioning on, the service keeps prior copies of an object instead of discarding them when it changes, so you can recover an earlier one. See Object versioning below.

A bucket must be empty before it can be deleted. The service refuses to delete a bucket that still holds objects, so remove its objects first.

An object is a single piece of stored data, for example an image, an archive, or a backup, together with the metadata that describes it. Each object is identified by a key within its bucket, a path-like string such as images/2026/logo.png. The key looks like a file path, but objects live in a flat namespace: the slashes are part of the name, not real folders. You can still list objects by a shared prefix to browse them as if they were directories.

Along with its bytes, every object carries metadata you can read without downloading the body:

  • its size,
  • a content type, the MIME type such as image/png,
  • a checksum that fingerprints the stored content,
  • the last-modified time,
  • an optional set of user metadata key-value pairs you attach yourself,
  • the storage class the object is stored in,
  • and, when the bucket has versioning on, a version identifier.

Object listings are narrowed with prefix and delimiter, not with the platform’s filter parameter. prefix restricts results to keys that begin with a string, and delimiter collapses everything after its next occurrence into a shared prefix, which is how a flat namespace is browsed as though it had folders:

Terminal window
curl --get https://api.qibdo.example.com/storage/v1/workspaces/$WORKSPACE/engines/qibdo/buckets/$BUCKET/objects \
--header "Authorization: Bearer $QIBDO_API_TOKEN" \
--data-urlencode "prefix=images/2026/" \
--data-urlencode "delimiter=/"

This listing accepts no filter, and that is a property of object storage rather than a gap in the API. A bucket is a flat keyspace, not a table. There are no indexed columns for a predicate to be evaluated against, so answering a query like “objects larger than 10 MB” would mean reading the metadata of every object in the bucket and discarding most of it. On a bucket holding millions of keys that is not a filter, it is a full scan billed to the caller.

What the keyspace is built for is ordered traversal by key, which is exactly what prefix and delimiter express. Narrow by prefix first, then apply any further conditions on the page you get back. Listing multipart uploads follows the same reasoning and takes prefix only.

Every other qibdo Cloud listing uses the AIP-160 filter language described in Filtering.

Versioning is a per-bucket setting with three positions, not two. Disabled, writing to an existing key replaces the object in place. Enabled, each write preserves the previous content as a distinct version, addressable by its own version identifier, so you can recover or roll back to an earlier copy. Suspended stops new versions being created but keeps every version already written, which goes on costing storage: it is not the same as off, and it is the state a bucket lands in when someone tries to turn versioning back off.

That last point is a one-way door. Once a bucket has been versioned it can be suspended but never returned to disabled, because the versions already written have to stay addressable.

The consequence worth knowing before you turn it on is what happens when you delete. Upload images/logo.png twice and then delete it:

StepVersions of images/logo.pngStored
uploadv1 (2.1 MB) — current2.1 MB
upload againv1 (2.1 MB) — previous
v2 (2.4 MB) — current
4.5 MB
deletev1 (2.1 MB) — previous
v2 (2.4 MB) — previous
v3 — delete marker
still 4.5 MB

The object stops appearing in listings and reads return a not-found error, but nothing was deleted and nothing was freed — the delete added a marker rather than removing anything. That is what makes the deletion recoverable, and it is also why a versioned bucket keeps growing until you remove the versions themselves.

Object lifecycle covers this in full: how to recover a deleted object, and which operation actually frees storage.

Every object carries a checksum derived from its content. Because identical content always yields the same checksum, you can compare the value the service reports against one you compute locally to confirm an upload or download arrived intact. Objects assembled from several parts use a checksum computed from those parts, so treat it as an identifier for that specific assembly rather than a plain digest of the whole.