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:
- Define Supabase service architecture and integration approach
- Create database operation patterns and best practices
- Set up authentication and authorization patterns
- Establish real-time and subscription patterns
- 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
