> ## Documentation Index
> Fetch the complete documentation index at: https://payload-storage-bunny.seshuk.im/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage

> Configure the Bunny Storage block for files, images, and documents, including S3 mode and per-collection zones.

Bunny Storage holds regular files: images, documents, and anything that isn't routed to [Bunny Stream](/configuration/stream/overview). It is the `storage` block passed to `bunnyStorage(...)`. This page also covers browser-direct [client uploads](/configuration/storage/client-uploads), which are configured under `storage.clientUploads`.

```ts payload.config.ts theme={null}
bunnyStorage({
  collections: { media: true },
  storage: {
    apiKey: process.env.BUNNY_STORAGE_API_KEY,
    hostname: process.env.BUNNY_STORAGE_HOSTNAME, // pull-zone host, e.g. my-zone.b-cdn.net
    zoneName: process.env.BUNNY_STORAGE_ZONE_NAME,
  },
})
```

## Options

| Option             | Type                | Required | Default        | Description                                                                                                                        |
| ------------------ | ------------------- | -------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`           | `string`            | Required | –              | Bunny Storage API key (the Storage Zone password).                                                                                 |
| `hostname`         | `string`            | Required | –              | CDN domain from your Pull Zone, e.g. `example.b-cdn.net`.                                                                          |
| `zoneName`         | `string`            | Required | –              | Your Storage Zone name.                                                                                                            |
| `region`           | `string`            | Optional | primary region | Storage region code: `br`, `jh`, `la`, `ny`, `se`, `sg`, `syd`, `uk`, or a custom string.                                          |
| `s3`               | `object`            | Optional | –              | S3-compatible access for the zone. See [S3 mode](#s3-mode).                                                                        |
| `tokenSecurityKey` | `string`            | Optional | –              | Security key for signing storage URLs. Required if you enable [signed URLs](/configuration/signed-urls) for storage.               |
| `uploadTimeout`    | `number`            | Optional | `120000` (ms)  | Upload timeout, in milliseconds. Can be overridden per collection.                                                                 |
| `clientUploads`    | `boolean \| object` | Optional | –              | Browser-direct uploads that bypass the Payload server for file bytes. See [Client uploads](/configuration/storage/client-uploads). |

<Info>
  The top-level `storage` block is optional. If every collection points at [its own storage zone](/configuration/collection-overrides), you can omit the global `storage` entirely — the plugin only requires that each collection resolves to at least one active service.
</Info>

## Getting your credentials

<Steps>
  <Step title="apiKey">
    Bunny Storage dashboard → your Storage Zone → **FTP & API Access** → copy the **Password** (use the full password, not the read-only one).
  </Step>

  <Step title="zoneName">
    The **Username** shown in the same panel.
  </Step>

  <Step title="hostname">
    Your **Pull Zone** hostname (not the Storage API endpoint). Bunny Storage needs a Pull Zone configured in front of it; files aren't reachable without one. See [Bunny's guide on accessing storage files](https://support.bunny.net/hc/en-us/articles/8561433879964-How-to-access-and-deliver-files-from-Bunny-Storage?ref=fndfoymy0j).
  </Step>

  <Step title="region">
    Read from your Storage Zone's endpoint hostname. For example, `ny.storage.bunnycdn.com` means region `ny`. Leave it out to use the default region.
  </Step>
</Steps>

## S3 mode

Setting `storage.s3` makes the plugin upload and delete files through Bunny's S3-compatible endpoint (SigV4-signed requests) instead of the HTTP Storage API. It also switches [client uploads](/configuration/storage/client-uploads) to presigned S3, where the browser sends a presigned PUT straight to that endpoint (no Edge Script needed).

<Warning>
  The zone must have been **created** with S3 compatibility enabled — it can't be turned on for an existing zone.
</Warning>

No extra secrets are needed: the S3 access key is your `zoneName` and the secret is your `apiKey` (the Storage Zone password) from the config above.

```ts payload.config.ts theme={null}
storage: {
  apiKey: process.env.BUNNY_STORAGE_API_KEY,
  hostname: 'example.b-cdn.net',
  zoneName: 'my-zone',
  s3: {
    region: 'de', // the region the zone was created in
  },
},
```

`s3.region` is the region the zone was created in; the endpoint becomes `https://{region}-s3.storage.bunnycdn.com`. Valid codes are `de`, `jh`, `la`, `ny`, `se`, `sg`, `syd`, `uk`, or a custom string.

<Info>
  This list isn't the same as `storage.region` above — the S3 region codes include `de` and omit `br`.
</Info>

See [Client uploads](/configuration/storage/client-uploads) for how S3 mode powers browser-direct uploads.

## Requirements

The plugin validates these on startup and throws a clear error if any fails:

* `hostname` must be your Pull Zone host. The plugin rejects a `hostname` containing `storage.bunnycdn.com`.
* If you turn on [signed URLs](/configuration/signed-urls) anywhere `storage` is active, `tokenSecurityKey` becomes required.
* `s3.region` is required when S3 mode is enabled.

## Collection overrides

A collection's `storage` can be one of three things:

* a **partial override** (`uploadTimeout`, `clientUploads`) — merged onto the global zone;
* a **full config** (with its own `apiKey`/`hostname`/`zoneName`) — this collection uses its OWN storage zone, ignoring the global zone entirely;
* **`false`** — disable Bunny Storage for this collection.

```ts payload.config.ts theme={null}
collections: {
  // Partial override — tweak the global zone
  largeFiles: {
    storage: {
      uploadTimeout: 300000, // 5 minutes for this collection only
    },
  },
  // Full config — this collection uses its own zone
  tenantA: {
    storage: {
      apiKey: process.env.TENANT_A_STORAGE_API_KEY,
      hostname: 'tenant-a.b-cdn.net',
      zoneName: 'tenant-a-zone',
      region: 'de',
      tokenSecurityKey: process.env.TENANT_A_TOKEN_SECURITY_KEY,
    },
  },
  // Disable storage for this collection — only stream uploads allowed
  videosOnly: {
    storage: false,
  },
}
```

The plugin distinguishes a full config from a partial override by whether it includes `apiKey`. A full config **inherits nothing** from the global zone: omitted optional keys (`region`, `s3`, `tokenSecurityKey`, `clientUploads`, `uploadTimeout`) fall back to plugin defaults, never to the global zone's values. Provide that zone's own `tokenSecurityKey` if you enable [signed URLs](/configuration/signed-urls) for it.

See [Collection overrides](/configuration/collection-overrides) for the full-config vs partial-override rules and the complete list of options.
