Skip to content
Supabase Patterns logo

Supabase Patterns

> **Skill Purpose:** Backend-as-a-Service database patterns and integration strategies

SKILL.md

Full skill instructions

Supabase Patterns

Skill Purpose: Backend-as-a-Service database patterns and integration strategies


Core Skill Pattern

Objective: Establish comprehensive Supabase usage patterns for database operations, authentication, real-time features, and edge functions.

Universal Pattern:

  1. Define Supabase service architecture and integration approach
  2. Create database operation patterns and best practices
  3. Set up authentication and authorization patterns
  4. Establish real-time and subscription patterns
  5. Create edge function and serverless patterns

Key Decisions (Project-Specific):

  • Database schema complexity and relationship patterns
  • Authentication method and user management approach
  • Real-time feature requirements and subscription patterns
  • Edge function usage and serverless architecture
  • Data access patterns and security requirements

Project-Specific Implementation Notes

Customize per project:

  • Database complexity based on data requirements
  • Authentication based on user management needs
  • Real-time features based on user experience requirements
  • Edge functions based on serverless processing needs
  • Security patterns based on data sensitivity and compliance

Example Implementation (Supabase Backend Pattern)

Note: This is an example pattern using Supabase. Adapt backend service and configuration based on your specific project requirements and data architecture.

Prerequisites (Example)

  • Supabase project created and configured
  • Database schema designed
  • Authentication requirements defined

Example: Supabase Backend Implementation

Framework-Specific Example: This demonstrates Supabase patterns. Adapt for your backend service and database requirements.

1. Client Configuration Patterns

// Supabase client setup
import { createClient } from '@supabase/​supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

// Admin client for server-side operations
import { createClient as createAdminClient } from '@supabase/​supabase-js';
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;

export const supabaseAdmin = createAdminClient(supabaseUrl, supabaseServiceKey);

2. Database Operation Patterns

// CRUD operations with type safety
import { Database } from '@/​types/​database';

type User = Database['public']['Tables']['users']['Row'];
type UserInsert = Database['public']['Tables']['users']['Insert'];

// Create operation
async function createUser(userData: UserInsert) {
  const { data, error } = await supabase
    .from('users')
    .insert(userData)
    .select()
    .single();
    
  if (error) throw error;
  return data;
}

// Read operation with filters
async function getUsers(filters?: Partial<User>) {
  let query = supabase.from('users').select('*');
  
  if (filters) {
    Object.entries(filters).forEach(([key, value]) => {
      if (value !== undefined) {
        query = query.eq(key, value);
      }
    });
  }
  
  const { data, error } = await query;
  if (error) throw error;
  return data;
}

// Update operation
async function updateUser(id: string, updates: Partial<User>) {
  const { data, error } = await supabase
    .from('users')
    .update(updates)
    .eq('id', id)
    .select()
    .single();
    
  if (error) throw error;
  return data;
}

// Delete operation
async function deleteUser(id: string) {
  const { error } = await supabase
    .from('users')
    .delete()
    .eq('id', id);
    
  if (error) throw error;
}

3. Authentication Patterns

// Authentication with Supabase Auth
import { AuthError } from '@supabase/​supabase-js';

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

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

// Sign out
async function signOut() {
  const { error } = await supabase.auth.signOut();
  if (error) throw error;
}

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

// Auth state listener
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_IN') {
    // Handle sign in
  } else if (event === 'SIGNED_OUT') {
    // Handle sign out
  }
});

4. Real-time Subscription Patterns

// Real-time subscriptions
import { RealtimeChannel } from '@supabase/​supabase-js';

// Subscribe to table changes
function subscribeToTableChanges(
  table: string,
  callback: (payload: any) => void
): RealtimeChannel {
  return supabase
    .channel(`${table}_changes`)
    .on('postgres_changes', 
      { 
        event: '*', 
        schema: 'public', 
        table 
      }, 
      callback
    )
    .subscribe();
}

// Subscribe to specific row changes
function subscribeToRowChanges(
  table: string,
  rowId: string,
  callback: (payload: any) => void
): RealtimeChannel {
  return supabase
    .channel(`${table}_${rowId}`)
    .on('postgres_changes',
      {
        event: '*',
        schema: 'public',
        table,
        filter: `id=eq.${rowId}`
      },
      callback
    )
    .subscribe();
}

// Unsubscribe from changes
function unsubscribe(channel: RealtimeChannel) {
  supabase.removeChannel(channel);
}

5. File Storage Patterns

// File upload and storage
async function uploadFile(
  bucket: string,
  path: string,
  file: File,
  options?: {
    cacheControl?: string;
    upsert?: boolean;
  }
) {
  const { data, error } = await supabase.storage
    .from(bucket)
    .upload(path, file, options);
    
  if (error) throw error;
  return data;
}

// Get public URL
function getPublicUrl(bucket: string, path: string) {
  const { data } = supabase.storage
    .from(bucket)
    .getPublicUrl(path);
    
  return data.publicUrl;
}

// Download file
async function downloadFile(bucket: string, path: string) {
  const { data, error } = await supabase.storage
    .from(bucket)
    .download(path);
    
  if (error) throw error;
  return data;
}

// Delete file
async function deleteFile(bucket: string, path: string) {
  const { error } = await supabase.storage
    .from(bucket)
    .remove([path]);
    
  if (error) throw error;
}

6. Edge Function Patterns

// Edge function calls
async function callEdgeFunction<
  TParams = any,
  TResult = any
>(
  functionName: string,
  params?: TParams
): Promise<TResult> {
  const { data, error } = await supabase.functions.invoke<TResult>(
    functionName,
    { body: params }
  );
  
  if (error) throw error;
  return data;
}

// Example edge function calls
async function processPayment(paymentData: PaymentData) {
  return callEdgeFunction('process-payment', paymentData);
}

async function generateReport(reportParams: ReportParams) {
  return callEdgeFunction('generate-report', reportParams);
}

async function sendNotification(notificationData: NotificationData) {
  return callEdgeFunction('send-notification', notificationData);
}

7. Database Function Patterns

// Call database functions
async function callDatabaseFunction<TResult = any>(
  functionName: string,
  params?: any[]
): Promise<TResult> {
  const { data, error } = await supabase.rpc(functionName, params);
  
  if (error) throw error;
  return data;
}

// Example function calls
async function getUserProfile(userId: string) {
  return callDatabaseFunction('get_user_profile', [userId]);
}

async function updateLastSeen(userId: string) {
  return callDatabaseFunction('update_last_seen', [userId]);
}

8. Error Handling Patterns

// Custom error handling
class SupabaseError extends Error {
  constructor(
    message: string,
    public code?: string,
    public details?: any
  ) {
    super(message);
    this.name = 'SupabaseError';
  }
}

// Error handling wrapper
async function handleSupabaseOperation<T>(
  operation: () => Promise<T>
): Promise<T> {
  try {
    return await operation();
  } catch (error) {
    if (error instanceof Error) {
      throw new SupabaseError(
        error.message,
        (error as any).code,
        error
      );
    }
    throw error;
  }
}

// Usage example
const user = await handleSupabaseOperation(() =>
  createUser(userData)
);

9. Connection Management

// Connection pooling and optimization
class SupabaseManager {
  private static instance: SupabaseManager;
  private client: ReturnType<typeof createClient>;
  
  private constructor() {
    this.client = createClient(supabaseUrl, supabaseAnonKey, {
      auth: {
        persistSession: true,
        autoRefreshToken: true,
      },
      db: {
        schema: 'public',
      },
    });
  }
  
  static getInstance(): SupabaseManager {
    if (!SupabaseManager.instance) {
      SupabaseManager.instance = new SupabaseManager();
    }
    return SupabaseManager.instance;
  }
  
  getClient() {
    return this.client;
  }
}

export const supabaseManager = SupabaseManager.getInstance();

Integration Patterns

Next.js Integration

  • Server-side rendering with auth
  • API routes with Supabase client
  • Static generation with data fetching

Authentication Integration

  • JWT token management
  • Session persistence
  • Protected routes and middleware

Real-time Integration

  • WebSocket connections
  • Live data updates
  • Collaboration features

Stop Conditions

STOP operations and escalate if:

  • Database connection fails repeatedly
  • Authentication service unavailable
  • Real-time subscriptions disconnect frequently
  • Edge functions timeout or fail
  • Storage operations fail consistently

PAUSE operations if:

  • Database in maintenance mode
  • Migration in progress
  • Rate limits reached
  • Storage quota exceeded

Performance Optimization

Database Optimization:

  • Query optimization patterns
  • Index usage strategies
  • Connection pooling
  • Caching strategies

Real-time Optimization:

  • Subscription management
  • Connection pooling
  • Data filtering
  • Batch operations

Security Patterns

Data Security:

  • Row Level Security (RLS) implementation
  • API key management
  • Data encryption
  • Access control patterns

Authentication Security:

  • JWT token validation
  • Session management
  • Multi-factor authentication
  • Password policies