Radondocs

Listing & metadata

Enumerate objects with list() — prefixes, pagination via cursor and hasMore, delimiter "folders" — plus getMetadata() and exists() for inspecting single objects.

Three methods let you inspect what's in your bucket without downloading bytes: list() enumerates objects, getMetadata() inspects one, and exists() checks presence.

Listing objects

list() returns a single page of objects under an optional prefix. Call it with no arguments to list everything, or pass a prefix to scope it.

const page = await storage.list("avatars/");
for (const obj of page.objects) {
  console.log(obj.key, obj.size, obj.lastModified);
}

Each object is an ObjectSummary:

keystring

The object's full key.

sizenumber

Size in bytes.

etagstring | undefined

The entity tag, where the provider reports it.

lastModifiedDate | undefined

Last-modified time, where the provider reports it.

Pagination

list() never returns everything at once — providers cap page size (S3 at 1000). The result tells you whether there's more and how to get it:

objectsObjectSummary[]

The objects in this page.

prefixesstring[]

Common "folder" prefixes — populated only when you pass a delimiter.

cursorstring | undefined

An opaque continuation token. Pass it back as options.cursor for the next page. undefined when there are no more pages.

hasMoreboolean

true when more objects exist beyond this page.

Loop until hasMore is false, feeding cursor back in:

Walk every object under a prefix
let cursor: string | undefined;
const all = [];

do {
  const page = await storage.list("uploads/", { limit: 500, cursor });
  all.push(...page.objects);
  cursor = page.cursor;
} while (cursor);
limitnumber

Max objects per page. Providers cap this (S3 at 1000); Radon forwards it and reports the rest via cursor / hasMore.

cursorstring

The continuation token from a previous page's cursor.

delimiterstring

Group keys sharing a prefix up to this character into prefixes instead of returning every key — a "list folders, not files" view.

Folders with a delimiter

Object stores are flat — there are no real folders, just keys with slashes. A delimiter (usually "/") makes list() collapse everything below the next slash into a common prefix, so you can browse a hierarchy one level at a time.

List the top-level 'folders'
const page = await storage.list("uploads/", { delimiter: "/" });

page.prefixes; // ["uploads/2025/", "uploads/2026/"] — the "folders"
page.objects;  // only keys directly under "uploads/", not inside sub-prefixes

getMetadata()

getMetadata() fetches everything about one object except its bytes — size, content type, timestamps, and your user metadata.

const meta = await storage.getMetadata("avatars/ada.png");
meta.size;             // bytes
meta.contentType;      // "image/png"
meta.lastModified;     // Date
meta.etag;             // entity tag
meta.cacheControl;     // stored Cache-Control, if any
meta.metadata;         // your user metadata, e.g. { customerId: "cus_123" }
keystring
The object's key.
sizenumber
Size in bytes.
contentTypestring | undefined
The stored MIME type.
etagstring | undefined
The entity tag.
lastModifiedDate | undefined
Last-modified time.
cacheControlstring | undefined
The stored Cache-Control, if any.
contentDispositionstring | undefined
The stored Content-Disposition, if any.
versionIdstring | undefined

Object version id, on versioned buckets.

metadataRecord<string, string>

Your user metadata, echoed back.

rawunknown

The untouched provider response.

getMetadata throws when the object is missing

If the key doesn't exist, getMetadata() throws ObjectNotFoundError (with .provider and .key). Use exists() when you only need a yes/no and don't want to catch an error.

exists()

exists() returns a plain boolean — true if an object is at that key, false otherwise. It never throws for a missing object.

if (await storage.exists("avatars/ada.png")) {
  // ...
}

Under the hood this is a HEAD request on the S3 family (cheap — no body), and the provider's nearest equivalent elsewhere.

Targeting a provider

Like every operation, list, getMetadata, and exists accept a { provider } option to override the default:

await storage.list("uploads/", { provider: "r2", limit: 100 });

list() uses the primary provider under failover

With a failover chain configured, list() always targets the primary provider — it doesn't merge listings across the chain. Pass { provider } to list a specific backend.

On this page