ShipVeryFastShipVeryFast
Documentation

File uploads

Since the boilerplate already uses Supabase, the simplest way to add uploads is Supabase Storage. It gives you buckets with the same policy model as your tables, so access control feels familiar.

Create a bucket with policies

Create a bucket (for example avatars) and add a policy so a user can only write to their own folder.

create policy "own folder" on storage.objects
  for all using (
    bucket_id = 'avatars'
    and (storage.foldername(name))[1] = auth.uid()::text
  );

Upload from the client

Use the Supabase client to upload, scoped to the signed-in user.

const path = `${userId}/${file.name}`;
const { error } = await supabase.storage.from("avatars").upload(path, file);

Serve the file

For public assets, get a public URL. For private files, create a short-lived signed URL on the server so the file is never exposed.

const { data } = await supabase.storage
  .from("avatars")
  .createSignedUrl(path, 60); // valid for 60 seconds

Validate uploads

Check file type and size before accepting an upload, and prefer signed URLs for anything private. Never trust the client to enforce limits.