Skip to main content
This page covers reading objects from your server: get for the bytes, info for the facts, exists for a boolean, list for a page of keys, and signedReadUrl for a link that reads a private object without going through your server.
The records these return (BlobObject, BlobInfo, BlobDownload) are on Types.

get

body is a stream and nothing is buffered for you. Wrap it in a Response for the usual conversions:
A missing object throws a BlobError with code not_found, status 404. See Errors. There is no range option. For byte ranges, use an S3 client.

info

One HEAD request. The same record as get without the bytes, so reading a 2 GB object’s facts is cheap. A missing object throws not_found. metadata comes back from get and info only, with keys lowercased. See Metadata.

exists

The same HEAD request as info, answering false instead of throwing. If you need the etag, size or metadata anyway, call info() and catch not_found instead of making two round trips.

list

All three are optional. A full walk is a do ... while:
Each entry is a BlobObject: path, size, etag, timestamp and URLs. There is no contentType or metadata; reading those is one info() per object. prefix is the only filter. There is no query by owner, type or date, so “this user’s files” has to be a prefix you chose at upload time. An app that needs to query its files should keep its own table and treat the bucket as storage, not an index.

Public URLs

Every record on a public bucket already carries url; publicUrl gives you one for any path. It returns undefined on a private bucket and throws a TypeError for an empty path or one with a . or .. segment. The URL itself is built from the token, but whether the bucket has a public host at all is known only to the backend, so the first call on a fresh client fetches credentials. They are cached, so every call after that is local.

versionedUrl

versionedUrl is ${url}?v=${etag}, so it changes whenever the content does. Use it for a stable path that gets overwritten: if avatars/u7.png is replaced every time the user picks a new picture, url never changes and caches keep serving the old bytes. Pair it with cache: 'immutable' at upload. See Caching.

Private buckets

A private bucket has no public host, so url and versionedUrl are undefined on every record. Nothing in the code declares this: the SDK learns it from the backend when it fetches credentials, and objects are stored with Cache-Control: private. Reads go through signedReadUrl().

signedReadUrl

A time-limited URL anyone can GET. Use it on a private bucket, or for an object you do not want linked from a public page. All three are optional.

Use expiresAt, not expiresIn

expiresIn is what you asked for. expiresAt is what you got, and it can be sooner, because a link cannot outlive the credential that signed it. Cache the link until expiresAt, never until a deadline you compute yourself. This applies to signedUploadUrl too. The reason is on How signing works.

downloadAs

Sets Content-Disposition: attachment, so the browser saves the file under that name rather than rendering it. Unicode names arrive intact. The filename is signed into the URL, so it cannot be edited afterwards.

contentType

Overrides what storage answers with, without rewriting the object. Throws invalid_input if it is not a valid media type.

Next steps

Writing

put, metadata, conditional writes and multipart from the server.

Caching

What Cache-Control an object is stored with, and pairing it with versionedUrl.

Deleting

One path, a list, a prefix, and sweeping incomplete uploads.

Errors

BlobError, the code list, and BlobError.is.