Features

  • PostgreSQL database with Row Level Security
  • Real-time subscriptions
  • Authentication with social providers
  • File storage with CDN
  • Edge Functions
  • Vector embeddings for AI

Quick Start

npx capx-compose@latest my-app --plugins= supabase
cd my-app
npm run dev

Configuration

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_anon_key
SUPABASE_SERVICE_KEY=your_service_key

Client Setup

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);

export default supabase;

Authentication

Email/Password Auth

async function signUp(email: string, password: string) {
  const { data, error } = await supabase.auth.signUp({
    email,
    password,
    options: {
      emailRedirectTo: `${window.location.origin}/auth/callback`,
    },
  });
  
  return { data, error };
}

async function signIn(email: string, password: string) {
  const { data, error } = await supabase.auth.signInWithPassword({
    email,
    password,
  });
  
  return { data, error };
}

Social Authentication

async function signInWithProvider(provider: 'google' | 'github' | 'twitter') {
  const { data, error } = await supabase.auth.signInWithOAuth({
    provider,
    options: {
      redirectTo: `${window.location.origin}/auth/callback`,
    },
  });
  
  return { data, error };
}

Session Management

function useUser() {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    // Get initial session
    supabase.auth.getSession().then(({ data: { session } }) => {
      setUser(session?.user ?? null);
    });
    
    // Listen for auth changes
    const { data: { subscription } } = supabase.auth.onAuthStateChange(
      (_event, session) => {
        setUser(session?.user ?? null);
      }
    );
    
    return () => subscription.unsubscribe();
  }, []);
  
  return user;
}

Database Operations

CRUD Operations

// Create
async function createPost(post: Post) {
  const { data, error } = await supabase
    .from('posts')
    .insert(post)
    .select()
    .single();
  
  return { data, error };
}

// Read
async function getPosts() {
  const { data, error } = await supabase
    .from('posts')
    .select('*, author:users(name, avatar)')
    .order('created_at', { ascending: false });
  
  return { data, error };
}

// Update
async function updatePost(id: string, updates: Partial<Post>) {
  const { data, error } = await supabase
    .from('posts')
    .update(updates)
    .eq('id', id)
    .select()
    .single();
  
  return { data, error };
}

// Delete
async function deletePost(id: string) {
  const { error } = await supabase
    .from('posts')
    .delete()
    .eq('id', id);
  
  return { error };
}

Best Practices

  1. RLS Policies: Always enable Row Level Security
  2. Type Safety: Generate TypeScript types from schema
  3. Connection Pooling: Use connection pooling for high traffic
  4. Caching: Implement proper caching strategies
  5. Error Handling: Handle network and permission errors

Resources