> ## Documentation Index
> Fetch the complete documentation index at: https://vetta.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# storage

> Object storage on a fullstack app — client.storage.

Buckets and objects on the organization's `fullstack` [app](/docs/sdk/apps). Nine methods: three on buckets, six on objects. Every one takes an optional `app`; without it the organization's single `fullstack` app is used — none is `404 not_found`, two or more is `409 ambiguous_app` naming them. API detail: [Storage](/docs/api/storage).

```ts theme={"system"}
await client.storage.buckets.create("avatars", { public: true });
await client.storage.upload("avatars", "users/alice.json", { name: "Alice" });
const { bytes, contentType } = await client.storage.download("avatars", "users/alice.json");
```

## buckets.list

```ts theme={"system"}
client.storage.buckets.list(options?: { app? }): Promise<List<Bucket>>
```

`GET /v1/apps/{id}/storage/buckets`. A `Bucket` is `{ object: "bucket", name, public, created_at }`.

## buckets.create

```ts theme={"system"}
client.storage.buckets.create(name: string, options?: { app?, public? }): Promise<Bucket>
```

`POST /v1/apps/{id}/storage/buckets`. Private unless `public: true`. An existing name is `409 name_conflict`.

## buckets.delete

```ts theme={"system"}
client.storage.buckets.delete(name: string, options?: { app?, force? }): Promise<{ object: "bucket", name, deleted: true }>
```

`DELETE /v1/apps/{id}/storage/buckets/{bucket}`. A non-empty bucket is refused unless `force: true`, which empties it first.

## list

```ts theme={"system"}
client.storage.list(bucket: string, query?: { app?, prefix?, limit?, after? }): Promise<Page<StorageObject>>
```

`GET /v1/apps/{id}/storage/buckets/{bucket}/objects`, cursor-paginated, keys under `prefix`. A `StorageObject` is `{ object: "storage_object", bucket, key, size_bytes, content_type, etag, updated_at }`.

## upload

```ts theme={"system"}
client.storage.upload(bucket: string, key: string, data: Uint8Array | string | unknown, options?: { app?, contentType? }): Promise<StorageObject>
```

`PUT /v1/apps/{id}/storage/buckets/{bucket}/objects/{key}`, the bytes inline (up to 50 MiB). `Uint8Array` is sent as `application/octet-stream`, a `string` as `text/plain; charset=utf-8`, anything else is JSON-encoded as `application/json`; `contentType` overrides. A key may contain `/`; each segment is encoded for you.

## download

```ts theme={"system"}
client.storage.download(bucket: string, key: string, options?: { app? }): Promise<{ bytes: Uint8Array; contentType: string }>
```

`GET /v1/apps/{id}/storage/buckets/{bucket}/objects/{key}` — the bytes and the type they were stored under, through the API with your key.

## remove

```ts theme={"system"}
client.storage.remove(bucket: string, keys: string[], options?: { app? }): Promise<void>
```

One `DELETE /v1/apps/{id}/storage/buckets/{bucket}/objects/{key}` per key, in order. A key that is already gone is not an error, and the call resolves with nothing once every key is gone.

## signedUploadUrl

```ts theme={"system"}
client.storage.signedUploadUrl(bucket: string, key: string, options: { app?, contentType, expiresSeconds? }): Promise<SignedUrl>
```

`POST /v1/apps/{id}/storage/buckets/{bucket}/objects/{key}/upload-url`. A `SignedUrl` is `{ object: "signed_url", url, method, expires_at }`; `PUT` the bytes to `url` with the same `Content-Type` before `expires_at`. `expiresSeconds` is 60–3600, default 900.

## signedUrl

```ts theme={"system"}
client.storage.signedUrl(bucket: string, key: string, options?: { app? }): Promise<SignedUrl>
```

`GET /v1/apps/{id}/storage/buckets/{bucket}/objects/{key}?signed=true` — a one-hour `GET` URL for handing to a browser or another service.
