Creator
Storage

Supabase Storage

Setting up Supabase Storage as your storage provider.

Setup

  1. Create a Supabase project at supabase.com
  2. Go to Storage and create a bucket (e.g. avatars)
  3. Set the bucket to public if you want direct public URLs
  4. Set environment variables:
NEXT_PUBLIC_STORAGE_SERVICE="supabase"
NEXT_PUBLIC_SUPABASE_URL="https://xxx.supabase.co"
SUPABASE_SERVICE_ROLE_KEY="eyJ..."
SUPABASE_STORAGE_BUCKET="avatars"

SUPABASE_STORAGE_BUCKET defaults to "avatars" if not set.

How it works

The Supabase provider uses the Supabase JS client with the service role key:

function createSupabaseProvider(): StorageProvider {
  const bucket = process.env.SUPABASE_STORAGE_BUCKET || "avatars";

  return {
    async upload(file, key, contentType) {
      const { createClient } = await import("@supabase/supabase-js");
      const supabase = createClient(
        process.env.NEXT_PUBLIC_SUPABASE_URL!,
        process.env.SUPABASE_SERVICE_ROLE_KEY!
      );

      const { error } = await supabase.storage
        .from(bucket)
        .upload(key, file, { contentType, upsert: true });

      if (error) throw new Error(`Supabase upload failed: ${error.message}`);

      const { data: urlData } = supabase.storage
        .from(bucket)
        .getPublicUrl(key);

      return { url: urlData.publicUrl, key };
    },

    async delete(key) {
      // Similar setup, calls supabase.storage.from(bucket).remove([key])
    },
  };
}

The upsert: true option overwrites existing files with the same key, which is used when replacing avatars.

URL format

Supabase Storage public URLs follow this pattern:

{SUPABASE_URL}/storage/v1/object/public/{bucket}/{key}

For example: https://xxx.supabase.co/storage/v1/object/public/avatars/user-123.jpg

Important notes

  • The service role key (SUPABASE_SERVICE_ROLE_KEY) bypasses Row Level Security — never expose it on the client side
  • Make sure the bucket is set to public for direct URL access
  • The Supabase JS client is dynamically imported to avoid bundling it when R2 is used

On this page

We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.