> ## 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](/v4/configuration/stream/overview). It is the `storage` block passed to `bunnyStorage(...)`. This page also covers browser-direct [client uploads](/v4/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 | `'de'` | Region the zone was created in. See [Regions](#regions). |
| `s3` | `boolean` | Optional | `false` | `true` uses the zone's S3-compatible endpoint. See [S3 mode](#s3-mode). |
| `tokenSecurityKey` | `string` | Optional | – | Security key for signing storage URLs. Required if you enable [signed URLs](/v4/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](/v4/configuration/storage/client-uploads). |

<Info>
  The top-level `storage` block is optional. If every collection points at [its own storage zone](/v4/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`, and `storage.bunnycdn.com` means `de`. Leave it out for `de`.
  </Step>
</Steps>

## Regions

These codes autocomplete. Any other string is passed through, so a new Bunny region works without a plugin update. Codes with only the Edge (SSD) column are replication regions without a storage endpoint, so they cannot be the zone `region`.

| Code | Location | Standard (HDD) | Edge (SSD) | S3 | Stream |
| - | - | - | - | - | - |
| `de` | Frankfurt, DE (default) | Yes | Yes | Yes | Yes |
| `uk` | London, UK | Yes | Yes | Yes | Yes |
| `se` | Stockholm, SE | Yes | Yes | Yes | Yes |
| `ny` | New York, US | Yes | Yes | Yes | Yes |
| `la` | Los Angeles, US | Yes | Yes | Yes | Yes |
| `sg` | Singapore, SG | Yes | Yes | Yes | Yes |
| `syd` | Sydney, SYD | Yes | Yes | Yes | Yes |
| `br` | São Paulo, BR | Yes | Yes | – | Yes |
| `jh` | Johannesburg, SA | Yes | Yes | Yes | Yes |
| `cz` | Prague, CZ | – | Yes | – | – |
| `es` | Madrid, ES | – | Yes | – | – |
| `mi` | Miami, US | – | Yes | – | – |
| `wa` | Seattle, US | – | Yes | – | – |
| `hk` | Hong Kong, HK | – | Yes | – | – |
| `jp` | Tokyo, JP | – | Yes | – | – |

## S3 mode

Setting `storage.s3: true` 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](/v4/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 options above.

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

The S3 endpoint is `https://{region}-s3.storage.bunnycdn.com`, with the same `region` as above.

See [Client uploads](/v4/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](/v4/configuration/signed-urls) anywhere `storage` is active, `tokenSecurityKey` becomes required.

Set `serverURL` in your Payload config. Cropping, changing the focal point and duplicating a document make Payload download the stored file again. Without `serverURL`, Payload may call the wrong origin, or call it without the editor's session, and these operations fail when the collection uses Payload access control.

## Collection overrides

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

* a **partial override** (`uploadTimeout`, `clientUploads`) — merged onto the global zone;
* **full options** (with their 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 options — 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 full options from a partial override by whether it includes `apiKey`. Full options **inherit 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](/v4/configuration/signed-urls) for it.

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


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.