Back to docs

Cloudflare R2

Cloudflare R2 exposes an S3-compatible API and can be connected to Storage UI with an Account ID, Access Key ID, and Secret Access Key.

1. Create a bucket

  1. Open R2 Object Storage in the Cloudflare dashboard.
  2. Select Create bucket.
  3. Enter a unique bucket name.
  4. Create the bucket and keep its name for the Storage UI configuration.

2. Create API credentials

Open R2 Object Storage -> Manage API tokens, then create an Account API token.

Choose the minimum permission required:

  • Object Read & Write for full file management.
  • Object Read when the connection will only be used in read-only mode.

Limit the token to the required bucket when possible. After creating it, save these values:

  • Access Key ID
  • Secret Access Key
  • Account ID

The Secret Access Key is only displayed once. Store it securely and never expose it through a NEXT_PUBLIC_* variable.

See the Cloudflare R2 API token documentation for the current dashboard flow and permission options.

3. Configure Storage UI

Add the connection to .env.local for local development, or to the environment variable settings on your deployment platform:

STORAGE_1_PROVIDER=r2
STORAGE_1_NAME=Cloudflare R2
STORAGE_1_BUCKET=my-bucket
STORAGE_1_ACCOUNT_ID=your-cloudflare-account-id
STORAGE_1_ACCESS_KEY_ID=your-access-key-id
STORAGE_1_SECRET_ACCESS_KEY=your-secret-access-key

Replace my-bucket with the exact bucket name created in Cloudflare.

Storage UI always builds the R2 endpoint from STORAGE_1_ACCOUNT_ID (https://<account-id>.r2.cloudflarestorage.com) - R2 has no custom-endpoint option, so a STORAGE_1_ENDPOINT value would simply be ignored. Double-check the Account ID: a missing or incorrect value isn't caught up front, and instead surfaces later as a connection or DNS error.

4. Optional settings

Enable read-only mode when the API token only has read access, or when users should not modify objects:

STORAGE_1_READ_ONLY=true

If the bucket is available through a public domain or CDN, configure its public base URL:

STORAGE_1_PUBLIC_BASE_URL=https://files.example.com

5. Restart Storage UI

Restart the development server after changing .env.local:

bun run dev

For a hosted deployment, save the environment variables and redeploy the application. The Cloudflare R2 connection will then appear in the sidebar.

Troubleshooting

The bucket does not appear

Confirm that the bucket name, Account ID, Access Key ID, and Secret Access Key are all configured under the same STORAGE_n_* number. A connection with a missing Account ID still loads - it just fails at request time, so a bucket that appears in the sidebar but stays empty or errors on open is usually a wrong or missing STORAGE_n_ACCOUNT_ID.

Access is denied

Check that the API token has access to the selected bucket. Full file management requires Object Read & Write permission.

Reading works but uploads fail

Confirm that STORAGE_n_READ_ONLY is not set to true and that the API token includes write permission.

Requests fail with a connection or DNS error

The endpoint is derived from STORAGE_n_ACCOUNT_ID as https://<account-id>.r2.cloudflarestorage.com. Since this value isn't validated when the connection loads, a typo or missing Account ID only shows up once a request is made.