Storage Buckets
Buckets are containers for organizing files in ZendBX Storage. Each bucket is scoped to a project and can be public or private.
Creating Buckets
typescript
const { data: bucket, error } = await db.storage.createBucket('user-uploads', {
description: 'Files uploaded by users',
isPublic: false,
});
console.log(bucket);
// {
// id: "550e8400-e29b-41d4-a716-446655440000",
// slug: "user-uploads",
// name: "user-uploads",
// description: "Files uploaded by users",
// is_public: false,
// created_at: "2024-01-15T10:30:00Z",
// project_id: "..."
// }| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | required | Bucket name (auto-generates slug) |
| description | string | optional | Optional description |
| isPublic | boolean | optional | Public access (default: false) |
Bucket Slugs
Bucket slugs are auto-generated from the name. They are:
- Lowercase
- Spaces converted to hyphens
- Special characters removed
- Unique within a project
typescript
// Valid bucket names
"user-uploads" → slug: "user-uploads"
"User Uploads" → slug: "user-uploads"
"My Documents 2024" → slug: "my-documents-2024"
// Invalid characters are stripped
"User's Files!!!" → slug: "users-files"Accessing Buckets
typescript
// Access bucket by slug (preferred)
const bucket = db.storage.bucket('user-uploads');
// Access by UUID (backward compatibility)
const bucketById = db.storage.bucket('550e8400-e29b-41d4-a716-446655440000');
// Both work identically - backend resolves automatically💡Always use slugs in new code. UUID support exists for backward compatibility only.
Public vs Private Buckets
Private Buckets (Default)
Files require authentication to access. Use for:
- User-uploaded documents
- Private photos and videos
- Confidential files
- Any user-specific data
Public Buckets
typescript
// Public bucket - files accessible without auth
await db.storage.createBucket('public-assets', {
description: 'Logos, icons, public images',
isPublic: true,
});Files are accessible without authentication. Use for:
- Company logos and branding
- Public marketing assets
- Open-source files
- Static website content
⚠️Never use public buckets for user data, documents, or anything requiring access control.
Listing Buckets
typescript
const { data: buckets, error } = await db.storage.listBuckets();
buckets.forEach(bucket => {
console.log(`${bucket.name} (${bucket.slug})`);
console.log(` Public: ${bucket.is_public}`);
console.log(` Files: ${bucket.file_count}`);
console.log(` Size: ${bucket.total_size} bytes`);
});Getting Bucket Info
typescript
const bucket = db.storage.bucket('user-uploads');
const { data: info, error } = await bucket.info();
console.log(info);
// {
// id: "...",
// slug: "user-uploads",
// name: "user-uploads",
// description: "Files uploaded by users",
// is_public: false,
// file_count: 142,
// total_size: 5242880, // bytes
// created_at: "2024-01-15T10:30:00Z"
// }Updating Buckets
typescript
// Update bucket metadata
const { data, error } = await db.storage.updateBucket('user-uploads', {
description: 'Updated description',
isPublic: true,
});Deleting Buckets
typescript
// Delete bucket (files must be deleted separately)
const { error } = await db.storage.deleteBucket('old-bucket');⚠️Deleting a bucket does NOT delete its files. Files must be deleted separately to avoid orphaned data.
Row-Level Security
Protect buckets and files with PostgreSQL RLS policies:
sql
-- Enable RLS on storage buckets
ALTER TABLE storage_buckets ENABLE ROW LEVEL SECURITY;
-- Users can only access buckets in their projects
CREATE POLICY "Users can access own project buckets"
ON storage_buckets
FOR ALL
USING (
project_id IN (
SELECT project_id FROM project_members
WHERE user_id = auth.uid()
)
);
-- Similar policy for storage_objects
CREATE POLICY "Users can access own project files"
ON storage_objects
FOR ALL
USING (
project_id IN (
SELECT project_id FROM project_members
WHERE user_id = auth.uid()
)
);💡RLS policies apply to both buckets and files. Always test policies with the anon key before deploying.
Storage Quotas
typescript
// Check storage quota
const { data: usage } = await db.storage.getUsage();
console.log(usage);
// {
// used: 5242880, // 5 MB
// limit: 1073741824, // 1 GB
// percentage: 0.48
// }Storage quotas are enforced at the project level:
- Free: 1 GB
- Pro: 100 GB
- Enterprise: Custom limits
Best Practices
- Use descriptive names:
user-avatarsnotbucket1 - Organize by purpose: Separate buckets for avatars, documents, images, etc.
- Default to private: Only make buckets public when absolutely necessary
- Enable RLS: Use Row-Level Security for multi-tenant apps
- Monitor usage: Track storage and transfer to avoid quota limits
- Use slugs: Reference buckets by slug, not UUID
Bucket Limits
| Parameter | Type | Required | Description |
|---|---|---|---|
| Max buckets | number | optional | 100 per project |
| Max bucket name length | number | optional | 63 characters |
| Max files per bucket | number | optional | Unlimited |
| Max file size | string | optional | 5 GB (configurable) |

