TechLead
Lesson 5 of 8
5 min read
Supabase

Supabase Storage

Store and serve files with Supabase Storage buckets and policies

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

Continue Learning