Create buckets, upload files from the browser, serve images with transformation URLs, and set policies.
// In SQL Editor:
-- Or use the Storage UI in the dashboard
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);import { supabase } from './supabase';
async function uploadAvatar(file, userId) {
const fileExt = file.name.split('.').pop();
const filePath = `${userId}/avatar.${fileExt}`;
const { error } = await supabase.storage
.from('avatars')
.upload(filePath, file, {
upsert: true // replace if exists
});
if (error) throw error;
// Get the public URL
const { data } = supabase.storage
.from('avatars')
.getPublicUrl(filePath);
return data.publicUrl;
}
// In a React component:
async function handleFileInput(event) {
const file = event.target.files[0];
const url = await uploadAvatar(file, user.id);
setAvatarUrl(url);
}-- Allow users to upload to their own folder
CREATE POLICY 'Users upload own avatar' ON storage.objects
FOR INSERT WITH CHECK (
bucket_id = 'avatars' AND
auth.uid()::text = (storage.foldername(name))[1]
);
-- Public read for avatar bucket
CREATE POLICY 'Public read avatars' ON storage.objects
FOR SELECT USING (bucket_id = 'avatars');storage.upload(path, file) → storage.getPublicUrl(path) — the basic pattern.storage.objects.upsert: true to replace files without deleting first.