Skip to main content

Overview

Supabase is an open-source Firebase alternative that provides PostgreSQL database, authentication, real-time subscriptions, and storage. This guide walks you through integrating Supabase into your Emergent application.
Supabase is perfect when you need a powerful relational database with real-time capabilities and built-in authentication.

What You’ll Build

By the end of this guide, you’ll have:
  • Supabase PostgreSQL database connected
  • CRUD operations for your data
  • Real-time subscriptions (optional)
  • Supabase Authentication (optional)
  • File storage (optional)

Prerequisites

1

Supabase Account

Create a free account at supabase.com
2

Create Project

Create a new Supabase project
3

Get Credentials

Copy your project URL and API keys

Step 1: Create Supabase Project & Get Credentials

Create Supabase Project

  1. Go to https://supabase.com
  2. Sign up or log in
  3. Click New Project
  4. Fill in project details:
    • Name: Your project name
    • Database Password: Strong password (save this!)
    • Region: Choose closest to your users
  5. Click Create new project
  6. Wait ~2 minutes for project initialization

Get Your Credentials

  1. Once project is ready, go to SettingsAPI
  2. Copy these three values:

Project URL

Format: https://xxxxx.supabase.coUse: Both frontend and backend

Anon (Public) Key

Starts with: eyJhbGci...Use: Frontend (safe to expose)Length: Very long JWT token

Service Role Key

Starts with: eyJhbGci...Use: Backend (keep secret!)Note: Has full database access
Never expose the Service Role Key in frontend! It bypasses all security rules.

Step 2: Request Integration from Emergent Agent

Basic Database Integration

I need to integrate Supabase PostgreSQL database:

Purpose: Replace MongoDB with PostgreSQL for [your use case]

Supabase Credentials:
- Project URL: https://xxxxx.supabase.co
- Anon Key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
- Service Role Key: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Database Tables Needed:
- users: id (uuid), email (text), name (text), created_at (timestamp)
- posts: id (uuid), user_id (uuid), title (text), content (text), created_at (timestamp)
- comments: id (uuid), post_id (uuid), user_id (uuid), content (text), created_at (timestamp)

Features Required:
- CRUD operations for all tables
- Backend API endpoints
- Frontend client for data fetching
- Foreign key relationships

Technical Setup:
- Backend: Supabase Python client for API endpoints
- Frontend: Supabase JS client for direct queries
- Create SQL migration script for tables

Please call integration_playbook_expert for Supabase setup.

With Authentication

I need Supabase with database and authentication:

Purpose: PostgreSQL database + Google social login

Supabase Credentials:
- Project URL: https://xxxxx.supabase.co
- Anon Key: eyJhbGci...
- Service Role Key: eyJhbGci...

Database Tables:
[List your tables]

Authentication:
- Google social login
- Email/password signup
- Protected routes
- User session management

Setup:
- Backend: API with Supabase auth
- Frontend: Login UI + auth context
- Database: User profiles table

Please call integration_playbook_expert.

With Real-Time Features

I need Supabase with real-time subscriptions:

Purpose: Chat app with real-time message updates

Supabase Credentials:
- Project URL: https://xxxxx.supabase.co
- Anon Key: eyJhbGci...
- Service Role Key: eyJhbGci...

Real-Time Features:
- Subscribe to new messages
- Live updates without refresh
- Typing indicators
- Online presence

Database Tables:
- messages: id, room_id, user_id, content, created_at
- rooms: id, name, created_at

Setup:
- Backend: Message API endpoints
- Frontend: Real-time subscription to messages table

Please call integration_playbook_expert.

Step 3: What the Integration Agent Will Create

Backend Implementation

1. Environment Variables (/app/backend/.env)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_KEY=your_service_role_key_here
2. Supabase Client Setup
from supabase import create_client, Client
import os

supabase_url = os.environ.get("SUPABASE_URL")
supabase_key = os.environ.get("SUPABASE_KEY")
supabase: Client = create_client(supabase_url, supabase_key)
3. API Endpoints
@app.get("/api/users")
async def get_users():
    try:
        response = supabase.table('users').select("*").execute()
        return {"users": response.data}
    except Exception as e:
        return {"error": str(e)}
@app.post("/api/users")
async def create_user(user_data: dict):
    try:
        response = supabase.table('users').insert(user_data).execute()
        return {"user": response.data[0]}
    except Exception as e:
        return {"error": str(e)}
@app.put("/api/users/{user_id}")
async def update_user(user_id: str, user_data: dict):
    try:
        response = supabase.table('users').update(user_data).eq('id', user_id).execute()
        return {"user": response.data[0]}
    except Exception as e:
        return {"error": str(e)}
@app.delete("/api/users/{user_id}")
async def delete_user(user_id: str):
    try:
        response = supabase.table('users').delete().eq('id', user_id).execute()
        return {"message": "User deleted successfully"}
    except Exception as e:
        return {"error": str(e)}
@app.get("/api/posts-with-users")
async def get_posts_with_users():
    try:
        response = supabase.table('posts').select(
            "*, users(id, name, email)"
        ).execute()
        return {"posts": response.data}
    except Exception as e:
        return {"error": str(e)}

Frontend Implementation

1. Environment Variables (/app/frontend/.env)
REACT_APP_SUPABASE_URL=https://xxxxx.supabase.co
REACT_APP_SUPABASE_ANON_KEY=your_anon_key_here
2. Supabase Client Setup
// src/supabaseClient.js
import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.REACT_APP_SUPABASE_URL
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY

export const supabase = createClient(supabaseUrl, supabaseAnonKey)
3. Using Supabase in Components
import { supabase } from './supabaseClient'
import { useState, useEffect } from 'react'

function UsersList() {
  const [users, setUsers] = useState([])
  const [loading, setLoading] = useState(true)
  
  useEffect(() => {
    fetchUsers()
  }, [])
  
  const fetchUsers = async () => {
    try {
      const { data, error } = await supabase
        .from('users')
        .select('*')
        .order('created_at', { ascending: false })
      
      if (error) throw error
      setUsers(data)
    } catch (error) {
      console.error('Error fetching users:', error)
    } finally {
      setLoading(false)
    }
  }
  
  if (loading) return <div>Loading...</div>
  
  return (
    <div>
      {users.map(user => (
        <div key={user.id}>
          <h3>{user.name}</h3>
          <p>{user.email}</p>
        </div>
      ))}
    </div>
  )
}
const createUser = async (userData) => {
  try {
    const { data, error } = await supabase
      .from('users')
      .insert([userData])
      .select()
    
    if (error) throw error
    
    console.log('User created:', data[0])
    return data[0]
  } catch (error) {
    console.error('Error creating user:', error)
  }
}

// Usage
await createUser({
  name: 'John Doe',
  email: 'john@example.com'
})
import { useEffect, useState } from 'react'
import { supabase } from './supabaseClient'

function RealTimeMessages() {
  const [messages, setMessages] = useState([])
  
  useEffect(() => {
    // Fetch initial messages
    fetchMessages()
    
    // Subscribe to new messages
    const subscription = supabase
      .channel('messages')
      .on('postgres_changes', 
        { 
          event: 'INSERT', 
          schema: 'public', 
          table: 'messages' 
        },
        (payload) => {
          console.log('New message:', payload.new)
          setMessages(prev => [payload.new, ...prev])
        }
      )
      .subscribe()
    
    // Cleanup
    return () => {
      subscription.unsubscribe()
    }
  }, [])
  
  const fetchMessages = async () => {
    const { data } = await supabase
      .from('messages')
      .select('*')
      .order('created_at', { ascending: false })
    
    setMessages(data || [])
  }
  
  return (
    <div>
      {messages.map(msg => (
        <div key={msg.id}>{msg.content}</div>
      ))}
    </div>
  )
}

Step 4: Create Database Tables in Supabase

1

Open Table Editor

In Supabase Dashboard, click Table Editor in sidebar
2

Create New Table

Click Create a new table
3

Define Table

  • Name: users
  • Enable Row Level Security: Check or uncheck
  • Columns: Define your columns
4

Add Columns

Click Add column for each field:
  • id (uuid, primary key, default: gen_random_uuid())
  • name (text)
  • email (text)
  • created_at (timestamptz, default: now())
5

Save Table

Click Save to create the table

Method 2: Using SQL Editor

  1. Go to SQL Editor in Supabase Dashboard
  2. Create a new query
  3. Run this SQL:
-- Create users table
CREATE TABLE users (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Create posts table
CREATE TABLE posts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  title TEXT NOT NULL,
  content TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Create comments table
CREATE TABLE comments (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  post_id UUID REFERENCES posts(id) ON DELETE CASCADE,
  user_id UUID REFERENCES users(id) ON DELETE CASCADE,
  content TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- Create indexes for better performance
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_comments_post_id ON comments(post_id);
CREATE INDEX idx_comments_user_id ON comments(user_id);

Method 3: Ask Agent to Generate SQL

Can you create SQL migration for Supabase with these tables:

**users table:**
- id (uuid, primary key)
- email (text, unique)
- name (text)
- avatar_url (text, nullable)
- created_at (timestamp)

**posts table:**
- id (uuid, primary key)
- user_id (uuid, foreign key to users)
- title (text)
- content (text)
- published (boolean, default false)
- created_at (timestamp)

**tags table:**
- id (uuid, primary key)
- name (text, unique)

**post_tags table (many-to-many):**
- post_id (uuid, foreign key to posts)
- tag_id (uuid, foreign key to tags)
- primary key (post_id, tag_id)

Include indexes for foreign keys and commonly queried fields.

Step 5: Enable Real-Time (Optional)

Enable Real-Time for Tables

  1. In Supabase Dashboard, go to DatabaseReplication
  2. Find your table (e.g., “messages”)
  3. Toggle Real-time to enabled
  4. Click Save

Frontend Real-Time Subscription

Already shown in Step 3 - Frontend Implementation section.

Step 6: Setup Row Level Security (RLS)

Production Security: Always enable RLS for production apps to protect your data.

What is RLS?

Row Level Security allows you to restrict which rows users can see and modify based on policies.

Enable RLS

  1. Go to AuthenticationPolicies
  2. Select your table
  3. Click Enable RLS

Create Policies

Example: Users can only see their own data
-- Policy: Users can read their own posts
CREATE POLICY "Users can view own posts"
  ON posts
  FOR SELECT
  USING (auth.uid() = user_id);

-- Policy: Users can insert their own posts
CREATE POLICY "Users can create posts"
  ON posts
  FOR INSERT
  WITH CHECK (auth.uid() = user_id);

-- Policy: Users can update their own posts
CREATE POLICY "Users can update own posts"
  ON posts
  FOR UPDATE
  USING (auth.uid() = user_id);

-- Policy: Users can delete their own posts
CREATE POLICY "Users can delete own posts"
  ON posts
  FOR DELETE
  USING (auth.uid() = user_id);
Example: Public read, authenticated write
-- Anyone can read posts
CREATE POLICY "Public posts are visible"
  ON posts
  FOR SELECT
  USING (published = true);

-- Authenticated users can create posts
CREATE POLICY "Authenticated users can create posts"
  ON posts
  FOR INSERT
  TO authenticated
  WITH CHECK (true);

Step 7: Setup Supabase Authentication (Optional)

Enable Auth Providers

  1. Go to AuthenticationProviders
  2. Enable desired providers:
    • Email/Password
    • Google
    • GitHub
    • etc.

Google OAuth Setup

1

Get Google Credentials

Create OAuth app in Google Cloud Console
2

Configure in Supabase

Add Client ID and Secret in Supabase
3

Set Redirect URL

Add redirect URL to Google OAuth app

Frontend Auth Implementation

import { supabase } from './supabaseClient'

// Sign up with email
const signUp = async (email, password) => {
  const { data, error } = await supabase.auth.signUp({
    email,
    password,
  })
  if (error) console.error('Error:', error)
  return data
}

// Sign in with email
const signIn = async (email, password) => {
  const { data, error } = await supabase.auth.signInWithPassword({
    email,
    password,
  })
  if (error) console.error('Error:', error)
  return data
}

// Sign in with Google
const signInWithGoogle = async () => {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider: 'google',
  })
}

// Sign out
const signOut = async () => {
  const { error } = await supabase.auth.signOut()
}

// Get current user
const getUser = async () => {
  const { data: { user } } = await supabase.auth.getUser()
  return user
}

Step 8: Test the Integration

1

Start Preview

Click Preview in Emergent
2

Test Database Operations

  • Try creating a record
  • Fetch and display records
  • Update a record
  • Delete a record
3

Check Supabase Dashboard

Verify data appears in Supabase Table Editor
4

Test Real-Time (if enabled)

  • Open app in two browser windows
  • Create record in one
  • Should appear in other instantly
5

Test Auth (if configured)

  • Try signing up
  • Try logging in
  • Check protected routes

Step 9: Deploy

Configure Environment Variables

In Emergent deployment settings, add: Backend:
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_KEY=your_service_role_key
Frontend:
REACT_APP_SUPABASE_URL=https://xxxxx.supabase.co
REACT_APP_SUPABASE_ANON_KEY=your_anon_key

Pre-Deployment Checklist

  • All tables created in Supabase
  • RLS policies configured (if using)
  • Environment variables set
  • Auth providers configured (if using)
  • Real-time enabled on required tables (if using)
  • Tested in Preview mode

Common Use Cases

Use Case 1: Blog Platform

I need Supabase for a blog platform:

**Tables:**
- users: author profiles
- posts: blog posts with rich content
- comments: reader comments
- tags: post categorization

**Features:**
- CRUD for posts
- Real-time comments
- User authentication
- Post search and filtering

Supabase credentials: [will provide]

Please call integration_playbook_expert.

Use Case 2: Real-Time Chat

I need Supabase for a chat application:

**Tables:**
- users: user profiles
- rooms: chat rooms
- messages: chat messages
- room_members: room membership

**Features:**
- Real-time message updates
- Typing indicators
- Online presence
- Message history
- User authentication

Supabase credentials: [will provide]

Please call integration_playbook_expert.

Troubleshooting

Error: “Failed to connect to Supabase”Solutions:
  • Verify Supabase URL is correct
  • Check API keys are correct
  • Ensure project is active (not paused)
  • Verify environment variables are loaded
Ask agent:
Supabase connection failing with error:
[paste error]

Can you verify the Supabase client configuration?
Error: “Row level security policy” or empty resultsSolutions:
  • Check if RLS is enabled
  • Verify policies allow the operation
  • Use service role key in backend (bypasses RLS)
  • Test with RLS disabled temporarily
Ask agent:
Supabase queries returning empty due to RLS.

Can you:
1. Check RLS policies
2. Update policies to allow [operation]
3. Or guide me to disable RLS for testing
Error: Subscriptions not receiving updatesSolutions:
  • Verify Real-time is enabled for table
  • Check subscription code is correct
  • Ensure listening for correct events
  • Check browser console for errors
Ask agent:
Real-time subscriptions not working for [table].

Updates in database but not appearing in UI.

Can you debug the real-time subscription code?

Best Practices

Security

  • Always use RLS in production
  • Never expose service role key in frontend
  • Use anon key for frontend
  • Validate data server-side
  • Use UUID for primary keys

Performance

  • Create indexes on foreign keys
  • Index frequently queried columns
  • Use select() to specify needed columns
  • Limit query results with .limit()
  • Use pagination for large datasets

Data Modeling

  • Use foreign keys for relationships
  • Set appropriate ON DELETE actions
  • Use TIMESTAMPTZ for timestamps
  • Add created_at/updated_at fields
  • Normalize data appropriately

Real-Time

  • Only enable for needed tables
  • Clean up subscriptions on unmount
  • Handle connection errors
  • Consider rate limiting
  • Use channels for grouping

Additional Resources

Supabase Docs

Official Supabase documentation

SQL Reference

PostgreSQL and Supabase SQL guide

RLS Guide

Row Level Security documentation

Supabase Dashboard

Manage your Supabase projects

Quick Reference

Integration Prompt

Integrate Supabase:

Credentials: [URL, anon key, service role key]
Tables: [List tables]
Features: [CRUD, real-time, auth]

Please call integration_playbook_expert.

Common Queries

// Select all
supabase.from('table').select('*')

// Select specific columns
supabase.from('table').select('id, name')

// With filter
supabase.from('table').select('*').eq('status', 'active')

// With join
supabase.from('posts').select('*, users(name, email)')

// Insert
supabase.from('table').insert([{...}])

// Update
supabase.from('table').update({...}).eq('id', id)

// Delete
supabase.from('table').delete().eq('id', id)
For Supabase questions, ask: “How do I [operation] with Supabase?” or “Show me an example of [feature] in Supabase.”