Supabase Storage
Supabase Storage lets you store and serve files like images, videos, and documents. It's built on S3-compatible object storage with built-in CDN and integrates with Supabase Auth for secure access control.
π Storage Features
- Buckets: Organize files into containers
- Policies: Control access with RLS-like rules
- CDN: Global content delivery network
- Transformations: Resize and optimize images
Creating Buckets
Create buckets in the Supabase Dashboard or via SQL:
-- Create a public bucket
INSERT INTO storage.buckets (id, name, public)
VALUES ('avatars', 'avatars', true);
-- Create a private bucket
INSERT INTO storage.buckets (id, name, public)
VALUES ('documents', 'documents', false);
Uploading Files
// Upload a file
const { data, error } = await supabase.storage
.from('avatars')
.upload('user-123/avatar.png', file, {
cacheControl: '3600',
upsert: false
})
// Upload with custom content type
const { data, error } = await supabase.storage
.from('documents')
.upload('report.pdf', file, {
contentType: 'application/pdf'
})
React File Upload
function FileUpload() {
const handleUpload = async (e) => {
const file = e.target.files[0]
const fileExt = file.name.split('.').pop()
const fileName = `${Date.now()}.${fileExt}`
const { data, error } = await supabase.storage
.from('uploads')
.upload(fileName, file)
if (error) {
console.error('Upload error:', error)
} else {
console.log('Uploaded:', data.path)
}
}
return
}
Downloading Files
// Download file as blob
const { data, error } = await supabase.storage
.from('documents')
.download('report.pdf')
// Get public URL (for public buckets)
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('user-123/avatar.png')
console.log(data.publicUrl)
// Get signed URL (for private buckets)
const { data, error } = await supabase.storage
.from('documents')
.createSignedUrl('report.pdf', 3600) // expires in 1 hour
Listing Files
// List files in a folder
const { data, error } = await supabase.storage
.from('uploads')
.list('user-123', {
limit: 100,
offset: 0,
sortBy: { column: 'created_at', order: 'desc' }
})
Deleting Files
// Delete a single file
const { error } = await supabase.storage
.from('uploads')
.remove(['user-123/old-file.png'])
// Delete multiple files
const { error } = await supabase.storage
.from('uploads')
.remove(['file1.png', 'file2.png', 'file3.png'])
Storage Policies
Control access to your files with storage policies:
-- Allow authenticated users to upload to their folder
CREATE POLICY "Users can upload own files"
ON storage.objects FOR INSERT
TO authenticated
WITH CHECK (
bucket_id = 'uploads' AND
(storage.foldername(name))[1] = auth.uid()::text
);
-- Allow users to read their own files
CREATE POLICY "Users can read own files"
ON storage.objects FOR SELECT
TO authenticated
USING (
bucket_id = 'uploads' AND
(storage.foldername(name))[1] = auth.uid()::text
);
-- Allow anyone to read public avatars
CREATE POLICY "Public avatar access"
ON storage.objects FOR SELECT
TO anon, authenticated
USING (bucket_id = 'avatars');
Image Transformations
// Get resized image URL
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('user-123/avatar.png', {
transform: {
width: 200,
height: 200,
resize: 'cover'
}
})
π‘ Key Takeaways
- β’ Use buckets to organize files by type or access level
- β’ Public buckets allow direct URL access
- β’ Private buckets require signed URLs
- β’ Storage policies work like RLS for files
- β’ Image transformations happen at the CDN edge
π Learn More
-
Storage Documentation β
Complete guide to Supabase Storage.
-
Image Transformations β
Resize and optimize images on the fly.