Migrate from Supabase Storage
Postgres-Native Cloud Storage is close to Supabase Storage in the storage schema, Bucket / Object metadata model, and RLS approach. If your application mainly uses Supabase File Buckets, you can migrate using this guide.
Before migration
Check your current Supabase Storage usage:
| Item | Description |
|---|---|
| Bucket type | General-purpose file buckets such as images, videos, documents, archives |
| Access model | Public / Private bucket, signed URL, authenticated download |
| RLS policies | SELECT / INSERT / UPDATE / DELETE on storage.objects |
| Path rules | <uid>/<filename>, <team_id>/<filename>, etc. |
| Upload restrictions | File size limit and MIME type allowlist |
| SDK APIs | upload, download, list, remove, createSignedUrl, etc. |
Start with a low-risk bucket, such as avatars or a test attachment bucket.
Reusable parts
The following usually map directly or with small adjustments:
| Supabase Storage | CloudBase |
|---|---|
storage.buckets | storage.buckets |
storage.objects | storage.objects |
bucket_id | bucket_id |
name object path | name object path |
owner_id | owner_id |
metadata / user_metadata | metadata / user_metadata |
storage.foldername(name) | storage.foldername(name) |
storage.filename(name) | storage.filename(name) |
| Most RLS policy ideas | CloudBase RLS policies |
For example, user-folder isolation is usually very similar:
CREATE POLICY user_files_select ON storage.objects
FOR SELECT TO authenticated
USING (
bucket_id = 'user-files'
AND (storage.foldername(name))[1] = auth.uid()
);
Differences to review
Review public semantics
In CloudBase Postgres-Native mode, storage.buckets.public is metadata. It does not automatically bypass RLS. Public readability is still decided by the SELECT policy on storage.objects.
If a Supabase Public Bucket relies on "anyone with the URL can access it", add an explicit public-read policy after migration:
CREATE POLICY objects_public_read ON storage.objects
FOR SELECT TO anon, authenticated
USING (
EXISTS (
SELECT 1 FROM storage.buckets b
WHERE b.id = storage.objects.bucket_id
AND b.public
)
);
SDK initialization differs
Supabase:
import { createClient } from '@supabase/supabase-js';
const supabase = createClient('<project-url>', '<anon-key>');
const bucket = supabase.storage.from('avatars');
CloudBase:
import cloudbase from '@cloudbase/js-sdk';
const app = cloudbase.init({ env: '<env-id>' });
const bucket = app.storage.from('avatars');
Review response fields and URLs
Check these fields during migration:
- upload result object ID, path, and full path;
- signed URL fields such as
signedUrl/fullSignedURL; - public URL fields;
- error object shape;
- pagination fields such as
hasNextandnextCursor.
Redesign advanced capabilities when needed
If your Supabase project uses TUS resumable uploads, S3-compatible protocols, image transformations, specific CDN headers, or other advanced capabilities, verify the CloudBase equivalent and recommended access path before migrating that logic.
For common File Bucket scenarios, prioritize these stable capabilities:
- Bucket creation and configuration;
- upload / download;
- list objects;
- copy / move / delete;
- signed download / signed upload;
- RLS policies.
Recommended migration steps
1. Inventory buckets
Record a contract for each bucket:
Bucket: avatars
Purpose: user avatars
Public: false
Size limit: 5 MB
MIME: image/png, image/jpeg, image/webp
Path: <uid>/avatar.png
Permission: owner writes; read depends on business rules
2. Create buckets in CloudBase
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
VALUES (
'avatars',
'avatars',
false,
5 * 1024 * 1024,
ARRAY['image/png', 'image/jpeg', 'image/webp']
);
3. Migrate file bytes
Choose a method based on scale:
- Small scale: download through SDK and upload again.
- Medium scale: write a server-side batch migration script.
- Large scale: use object-storage backend tooling, then backfill metadata.
Store all credentials in environment variables. Do not commit Supabase service keys, CloudBase API Keys, or Tencent Cloud secrets.
4. Migrate metadata and business references
If business tables store Supabase file URLs, migrate them to stable bucket-relative paths instead:
avatars/user-123/avatar.png
Store object paths in business data, then generate public URLs or signed URLs at display time.
5. Migrate RLS policies
Migrate SELECT, INSERT, UPDATE, and DELETE policies bucket by bucket. Verify:
- owner can access their own files;
- non-owner cannot access private files;
- anonymous access matches expectations;
service_roleis used only on trusted backends.
6. Replace SDK calls
| Supabase | CloudBase |
|---|---|
supabase.storage.from(bucket) | app.storage.from(bucket) |
bucket.upload(path, file, options) | bucket.upload(path, file, options) |
bucket.download(path) | bucket.download(path) |
bucket.list(prefix, options) | bucket.list(prefix, options) |
bucket.remove(paths) | bucket.remove(paths) |
bucket.createSignedUrl(path, expiresIn) | bucket.createSignedUrl(path, expiresIn) |
bucket.getPublicUrl(path) | bucket.getPublicUrl(path) |
Similar method names do not guarantee identical response shapes. Use JS SDK Storage API as the source of truth.
7. Run permission regression tests
| Case | Expected result |
|---|---|
| Owner uploads own file | Success |
| Owner downloads own file | Success |
| Non-owner downloads private file | Fail |
| Anonymous reads public file | Depends on public-read policy |
| Anonymous reads private file | Fail |
| Owner overwrites own file | Depends on UPDATE policy |
| Non-admin deletes team file | Fail |
| Admin deletes team file | Success |
AI-friendly migration checklist
When asking AI to help migrate, provide a structured bucket contract:
Source: Supabase Storage
Target: CloudBase Postgres-Native Cloud Storage
Bucket: avatars
Purpose: user avatars
Path: <uid>/avatar.png
Public: no
Read: all signed-in users can read
Upload: only the owner can upload to their <uid>/ folder
Overwrite: only the owner can overwrite their avatar
Delete: only the owner can delete their avatar
Limits: 5 MB; image/png, image/jpeg, image/webp
Need: Bucket SQL, RLS policies, JS SDK upload and signed URL code