Browse docs
Docs / Admin & IT / Dedicated Storage Isolation

Dedicated Storage Isolation

Dedicated storage is the default for every new paid organization: your org gets its own physical bucket, reached through a credential that's scoped to that one bucket and cannot touch any other org's data - even a compromised or misused credential can't reach past your own bucket boundary. Free-plan orgs, orgs created before this became the default, and orgs that explicitly opted out at creation time fall back to the older model: one shared storage bucket, isolated from every other org by an application-level key prefix rather than a physical boundary.

This page is the operational how-to. For the underlying model - what "blast radius" means here and why the boundary is the org rather than the project - see Security Architecture.

What this does and doesn't change#

  • Physical isolation, not encryption. Dedicated storage is about where the bytes live, not what protects them once there - it closes the "a bug in our own code, or a leaked account-wide credential, could theoretically reach any org's bucket" gap that the default shared-bucket-plus-prefix model can't fully close on its own. Encryption at rest is a separate question with its own tiers: private projects on paid plans are encrypted; Free-plan and public projects are stored unencrypted (see Security).
  • Still our infrastructure, not yours. This is not bring-your-own-storage - your data stays in a bucket we create and operate on our own cloud infrastructure, just a bucket that's exclusively yours instead of shared. If your compliance requirement is specifically "our data must live in infrastructure we control," this isn't the right tier: for that, Bring-your-own-storage (Enterprise) makes a bucket on your own account the org's primary block storage, and a self-hosted Enterprise control plane (see Deployment Topologies) puts the control plane and storage both on infrastructure you control. Talk to us about which fits.
  • The org boundary, not the project boundary. One dedicated bucket covers every project in your org. Projects within it are still separated the same way they always were (a project-scoped prefix inside the bucket) - that separation was already correct and doesn't need its own bucket to be safe.

Requesting it#

New paid orgs select this automatically - there's nothing to request. Org creation records the storage choice but does not provision a bucket. The dedicated bucket is created only when the user deliberately creates the org's first project. API callers can also explicitly opt out at creation time with POST /orgs and blockIsolation: "shared".

If your org predates the default (or was created with the shared opt-out and you've changed your mind), an owner can still turn dedicated storage on from Settings → Storage - a one-click, one-way switch (see below).

Starter plan or above only. Free-plan orgs always use shared storage and aren't offered the switch at all; upgrading to Starter or Pro is the path onto dedicated storage, and the dedicated bucket is then created with the org's first project (or by the switch itself, if the org still has no files). The same rule is enforced server-side, not just hidden in the UI.

This only works before the org has any files. There's no migration path yet to move existing files into a new bucket, so switching is rejected outright once an org has uploaded anything. For an org that opted out at creation and wants to reconsider, that means: do it before adding content - not later as an afterthought.

The same page also carries your bucket's public-access switches when your org is on Bring-your-own-storage - anonymous streaming and gated release downloads served from a customer-supplied bucket. Shared and Swarmfile-managed dedicated buckets always stream and serve downloads, so those switches only appear in BYOS mode.

What happens during provisioning#

Provisioning isn't instant - creating the bucket and minting a credential scoped to it both involve real calls to our storage platform, and a freshly minted credential needs a few seconds to become valid before we'll rely on it. This begins when the first project is explicitly created, or on-demand when an existing eligible org turns the switch on from Settings → Storage. Until it finishes, the org's block storage briefly denies reads and writes rather than falling back to the shared bucket - a silent fallback would defeat the isolation guarantee, so a short, visible pause is the deliberate tradeoff. If provisioning hits a transient failure (an upstream API hiccup, for instance), it retries automatically on a lengthening schedule - about a minute at first, stretching out to daily for a persistent failure - so nothing needs to be re-requested by hand.

Known limitations today#

  • Empty orgs only. No migration path exists to move already-uploaded files into a new dedicated bucket - the switch is rejected if the org has any files. This isn't a request-and-wait limitation; it's enforced at the moment you ask. A Free-plan org that upgrades to a paid plan after uploading anything is in the same position: the upgrade gets dedicated storage for future work only when the org was still empty, and an org that already has files stays on shared storage.
  • One-way. There's no supported path to move an org that's already on dedicated storage back to the shared tier - the Storage page's switch only goes one direction, on purpose. Make sure this is what you want before turning it on.
  • No credential rotation yet. If you have a specific reason to believe your org's storage credential needs rotating, contact us directly rather than waiting on a self-service flow - none exists yet.
  • Owner-only. Admins and members don't see the Storage tab; only the org owner can turn it on - and a Free-plan org's owner can't turn it on at all (see above).

For API consumers#

GET /orgs/:orgId/block-bucket reports hasContent - whether the org already has files, the fact that decides eligibility for the one-way switch. It is only meaningful for a shared org and is computed with a cross-project lookup, so the hub skips that lookup and reports false for dedicated, byos, provisioning, and failed orgs; don't read false as "no files" in those modes. mode is the field to branch on everywhere.

The same response carries the raw Cloudflare storage accountId (and, for a dedicated org, the bucket name) for support and ops inspection. No dashboard surface renders them, and no client should branch on them - the Cloudflare account id is infrastructure detail, not an org identifier.