collections can use the global options as-is, or override individual options. This lets you keep one set of plugin options while giving each collection different behavior.
Collection options
prefix and disablePayloadAccessControl come from @payloadcms/plugin-cloud-storage and apply to every collection using this plugin. disableLocalStorage can’t be passed here — the plugin always sets it to true on managed collections.
Override surface: partial vs full replacement
Not every option can be tweaked in isolation. Some are partially overridable (merged onto the global zone/library); others exist only inside full replacement options and can never be set on their own. The plugin flipsstorage/stream into full-replacement mode the moment the object contains apiKey — see Own zone or library per collection.
How overrides merge
A partial override object (one withoutapiKey) is merged on top of the matching global option — it doesn’t replace the whole block. An object that includes apiKey isn’t a merge at all: it is a complete replacement of that zone/library, with every credential field required and nothing inherited — see Own zone or library per collection. For a partial override, for example:
Own zone or library per collection
A collection’sstorage or stream can go beyond a partial override and supply full options — its own apiKey, hostname, zoneName (storage) or libraryId (stream). That collection then uses its OWN Bunny zone / library, and the global one is ignored for it. This is how you point different collections at different tenants’ zones and libraries.
- How it’s detected. The plugin treats the override as full options when it contains
apiKey('apiKey' in override); otherwise it’s a partial override merged onto the global options.{ uploadTimeout: 5 }is a partial override;{ apiKey, hostname, zoneName }is full options. - No inheritance. Full options inherit nothing from the global zone/library. Omitted optional keys (storage:
region,s3,tokenSecurityKey,clientUploads,uploadTimeout; stream:mimeTypes,mp4Fallback,tus,referer, …) fall back to plugin defaults — never to the global options’ values. - Signed URLs. Provide that zone/library’s own
tokenSecurityKeywhen signed URLs are enabled for the collection. - Webhooks. A per-collection stream library can carry its own
webhook.secret; the single webhook endpoint accepts every configured secret. - Cleanup. Per-collection stream
cleanupcontrols onlymaxAge. The cleanupscheduleis global-only (one task for the whole plugin). - Client uploads travel with the zone. Full storage options’
clientUploads(including itsedgescript and secret) belongs to that zone and doesn’t merge with the globalstorage.clientUploads. - Top-level optional. Because a collection can own its whole zone/library, the top-level
storage/streamare optional — options made entirely of per-collection zones is valid.
apiKey/hostname/zoneName; full stream options need apiKey/hostname/libraryId. A single stream library must not be configured with conflicting apiKey values across collections.
Disabling a service or feature: use false
Some options accept false to turn a feature off for one collection, even if it is enabled globally.
payload.config.ts
purge, signedUrls, thumbnail, urlTransform, storage.clientUploads, and stream.tus all support false this way. A collection must keep at least one of storage or stream active — disabling both is an options error.
Enabling a collection with defaults
Passtrue instead of an object to use every global setting unmodified. false leaves the collection out, together with its hidden prefix field, so it changes the SQL schema. To turn the plugin on or off with an environment variable, use enabled.
Accessing the resolved options
Sometimes you need the settings the plugin resolved for a collection — the library id and API key for a Stream recipe, the zone name for a direct Storage call — from inside a hook, endpoint, or script. Rather than re-derive them fromprocess.env or hand-maintain a lookup, ask the plugin. These accessors read the options it stashed on payload.config.custom, with global options and per-collection overrides already applied.
Semantics:
payloadis a running Payload instance —req.payloadin a hook or endpoint, or the instance fromgetPayload(...)in a script.- Never throws. Each accessor returns
undefinedwhen the plugin is absent or disabled, the slug isn’t one of the plugin’scollections, or (for a per-backend accessor) that backend is off for the collection.getBunnyCollectionOptionsreturns an object for any managed slug — a backend the collection doesn’t use is simply absent from it. getBunnyOptionsis an escape hatch. It returns the plugin’s internal normalized shape, which may change between minor releases. Treat it as read-only and prefer the curated accessors above.- The curated results are fresh copies; mutating them doesn’t affect the plugin.