Buckets

Buckets are top-level containers for your files. Create them from the dashboard before uploading.

Creating a bucket

Navigate to your project in the dashboard, select Storage, and click New Bucket. Give the bucket a name — this is what you'll reference in the Flutter SDK.

Buckets must be created before uploading

Calling Koolbase.storage.upload() with a bucket name that doesn't exist will return a 404 error. Always create buckets from the dashboard first.

Access model

Every bucket has one of three access behaviors, chosen at creation and immutable after:

Public

Anyone with the URL can read. Files get stable CDN URLs — right for assets that are meant to be seen: product images, published content, avatars in a social app. See Public Buckets.

Private — Project mode (default)

Any authenticated user of your project can read and write any path. Reads go through time-limited signed URLs. Right for shared app content where all signed-in users may see everything.

Private — Owner mode

Each user can only read, overwrite, or delete files they uploaded — enforced on every SDK operation, including version history. Uploads require a signed-in user. Right for per-user private files: documents, health data, private photos.

In Project mode, paths are not privacy

A guessable path like avatars/{user_id}.jpg in a project-mode bucket is readable by every signed-in user of your project — anyone can construct another user's path. If files are per-user sensitive, use Owner mode. If you stay in Project mode, store objects under random, unguessable keys and reference them from database rows protected by read: owner rules — the database, not the object path, is your ownership boundary.

Owner-mode details worth knowing: denials answer 404 not-found — never confirming whether a path exists to someone who doesn't own it. Attempting to upload over another user's path answers 409. Uploads without a signed-in user are rejected with a clear error. Project admins working through the dashboard see and manage all files regardless of mode. Public + Owner is contradictory and rejected at creation.

Naming rules

Lowercase letters, numbers, and hyphens only
Maximum 63 characters
Must be unique within your project
Cannot start or end with a hyphen
Examples: avatars, user-uploads, product-images, documents

Bucket limits

Each bucket can be configured with three optional limits that the server enforces at upload time, before file bytes ever reach R2. Set them in the bucket creation modal in the dashboard (or via the bucket API).

max_size_bytes

Total bucket size cap. The sum of all file sizes in the bucket cannot exceed this. Leaving it unset means no quota.

max_file_size_bytes

Per-file size cap. Each upload is checked against this independently. Leaving it unset means no per-file limit.

allowed_mime_types

List of allowed content-types for uploads. Supports family wildcards: image/* matches every image type (PNG, JPEG, WebP, AVIF, ...). An empty or unset list accepts any type.

Limits are enforced at presign time

The check runs when your app requests the upload URL — before the file is sent. A bucket-limit rejection returns a typed error (KoolbaseStorageQuotaException, KoolbaseStorageFileTooLargeException, KoolbaseStorageMimeTypeException in Flutter; the matching Error classes in React Native and the browser) so no bandwidth is wasted on uploads that won't be accepted. See Upload Files for handling.

Recommended bucket structure

Organise buckets by file type or feature rather than by user. Use the file path within the bucket to scope files per user:

avatars/user_{userId}.jpg

Profile photos, one per user

attachments/posts/{postId}/{filename}

Post attachments, scoped by post

documents/{userId}/{filename}

User documents, scoped by user ID

thumbnails/products/{productId}.jpg

Product images, scoped by product

Deleting a bucket

Buckets can be deleted from the dashboard. Deleting a bucket removes all files within it from R2 and removes all file metadata from the database. This action is permanent and cannot be undone.

Deletion is permanent

Deleting a bucket deletes all files inside it. There is no trash or recovery. The dashboard requires you to type the bucket's name to confirm — exactly as written.