Platform

Storage

Object storage for files and assets with public and private buckets, upload streams, and signed URLs.

Every OrbitNest project includes managed object storage. Organize files into buckets, upload from any client, and serve content via direct URLs or signed links.

Buckets

A bucket is a named container for files. Buckets can be public (anyone with a URL can download) or private (requires a signed URL or authenticated request). Create buckets from Studio or programmatically.

typescript
// Create a public bucket for avatars
await client.storage.createBucket('avatars', { public: true });

// Create a private bucket for user documents
await client.storage.createBucket('documents', { public: false });

Uploading files

Upload Blob, File, or Uint8Array payloads. Files are stored with a key you provide — usually a path like userId/avatar.png.

typescript
// Browser / Flutter
const { path, url } = await client.storage
  .from('avatars')
  .upload(`${userId}/avatar.png`, file, {
    contentType: 'image/png',
    upsert: true,
  });

console.log(url); // publicly accessible for public buckets

Download URLs

Public buckets expose stable URLs via getPublicUrl(). The URL is deterministic —{baseUrl}/api/public/{projectSlug}/storage/{bucket}/{path} — and safe to cache or share. No query-string signing on public buckets.

typescript
const { url } = client.storage.from('avatars').getPublicUrl('jane/avatar.png');
// https://api.orbitnest.io/api/public/<slug>/storage/avatars/jane/avatar.png

Image transforms

Request an on-the-fly rendition of an image by passing transform to getPublicUrl() — resize, re-encode, and set quality without storing extra copies. Options: width, height, quality (1–100), format (webp/jpeg/png/avif), and fit (cover/contain/fill/inside/outside).

typescript
const { url } = client.storage.from('avatars').getPublicUrl('jane/avatar.png', {
  transform: { width: 128, height: 128, format: 'webp', quality: 80, fit: 'cover' },
});
// …/storage/avatars/jane/avatar.png?width=128&height=128&format=webp&quality=80&fit=cover

Flutter is the same shape via StorageTransform:

dart
final url = client.storage.from('avatars').getPublicUrl(
  'jane/avatar.png',
  transform: const StorageTransform(width: 128, format: 'webp', quality: 80),
);

For private buckets, access is gated by an authenticated request: include the caller's JWT (anon or service-role) on a GET to the storage path and the backend checks RLS policies onstorage.objects before streaming the bytes.

Signed URLs are on the roadmap

Time-limited signed URLs (a createSignedUrl() method returning a pre-signed link with an expiry) are not shipped yet. For now, keep private content behind the authenticated endpoint or proxy through an edge function that enforces your access rules.

Access policies

Buckets support policy-based access for fine-grained control. Policies are Postgres RLS policies on the storage.objects table.

sql
-- Users can upload to their own folder
CREATE POLICY "upload own files" ON storage.objects
  FOR INSERT WITH CHECK (
    bucket_id = 'documents'
    AND (storage.foldername(name))[1] = auth.uid()::text
  );

Listing and deleting

typescript
// List files in a bucket
const { data: files } = await client.storage
  .from('avatars')
  .list(userId, { limit: 100 });

// Delete files
await client.storage.from('avatars').remove(['old/avatar.png']);

Image transforms

Request a resized or reformatted rendition of an image on the fly — no need to pre-generate thumbnails. Pass a transform to getPublicUrl(), or append the query params (width, height, format, quality, fit) to any public image URL.

typescript
const { url } = client.storage.from('avatars').getPublicUrl('jane/avatar.png', {
  transform: { width: 128, height: 128, format: 'webp', quality: 80, fit: 'cover' },
});
// .../storage/avatars/jane/avatar.png?width=128&height=128&format=webp&quality=80&fit=cover

Renditions are generated with sharp and cached, so repeat requests are fast. SVGs and animated GIFs are served unchanged.

Limits

  • Max file size: 50 MB (Starter) / 500 MB (Pro) / configurable (Enterprise)
  • Bucket quota: see your pricing tier
  • Egress: counted against your plan's allowance
  • Supported content types: any — MIME is set on upload

Streaming uploads

Large files are uploaded in 5 MB chunks with automatic resume. The SDK handles retries transparently on network hiccups.