building-with-supabase

Building with Supabase

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "building-with-supabase" with this command: npx skills add doanchienthangdev/omgkit/doanchienthangdev-omgkit-building-with-supabase

Building with Supabase

Purpose

Build secure, scalable applications using Supabase's PostgreSQL platform:

  • Design tables with proper Row Level Security (RLS)

  • Implement authentication flows (email, OAuth, magic link)

  • Create real-time subscriptions for live updates

  • Build Edge Functions for serverless logic

  • Manage file storage with security policies

Quick Start

// Initialize Supabase client import { createClient } from '@supabase/supabase-js'; import { Database } from './types/supabase';

export const supabase = createClient<Database>( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! );

// Server-side with service role (bypasses RLS) import { createClient } from '@supabase/supabase-js'; export const supabaseAdmin = createClient<Database>( process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY! );

Features

Feature Description Guide

PostgreSQL Full Postgres with extensions (pgvector, PostGIS) Direct SQL or Supabase client

Row Level Security Per-row access control policies Enable RLS + create policies

Authentication Email, OAuth, magic link, phone OTP Built-in auth.users table

Real-time Live database change subscriptions Channel subscriptions

Edge Functions Deno serverless functions TypeScript at edge

Storage S3-compatible file storage Buckets with RLS policies

Common Patterns

RLS Policy Patterns

-- Enable RLS on table ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- Owner-based access CREATE POLICY "Users can CRUD own posts" ON posts FOR ALL USING (auth.uid() = user_id) WITH CHECK (auth.uid() = user_id);

-- Public read, authenticated write CREATE POLICY "Anyone can read posts" ON posts FOR SELECT USING (published = true);

CREATE POLICY "Authenticated users can create" ON posts FOR INSERT WITH CHECK (auth.uid() IS NOT NULL);

-- Team-based access CREATE POLICY "Team members can access" ON documents FOR ALL USING ( team_id IN ( SELECT team_id FROM team_members WHERE user_id = auth.uid() ) );

-- Role-based access using JWT claims CREATE POLICY "Admins can do anything" ON users FOR ALL USING (auth.jwt() ->> 'role' = 'admin');

Authentication Flow

// Sign up with email const { data, error } = await supabase.auth.signUp({ email: 'user@example.com', password: 'secure-password', options: { data: { full_name: 'John Doe' }, // Custom user metadata emailRedirectTo: 'https://app.com/auth/callback', }, });

// OAuth sign in const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'google', options: { redirectTo: 'https://app.com/auth/callback', scopes: 'email profile', }, });

// Magic link const { error } = await supabase.auth.signInWithOtp({ email: 'user@example.com', options: { emailRedirectTo: 'https://app.com/auth/callback' }, });

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

// Sign out await supabase.auth.signOut();

Real-time Subscriptions

// Subscribe to table changes const channel = supabase .channel('posts-changes') .on( 'postgres_changes', { event: '*', // INSERT, UPDATE, DELETE, or * schema: 'public', table: 'posts', filter: 'user_id=eq.' + userId, // Optional filter }, (payload) => { console.log('Change:', payload.eventType, payload.new); } ) .subscribe();

// Cleanup channel.unsubscribe();

Edge Functions

// supabase/functions/process-webhook/index.ts import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; import { createClient } from 'https://esm.sh/@supabase/supabase-js@2';

serve(async (req) => { const supabase = createClient( Deno.env.get('SUPABASE_URL')!, Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')! );

const { record } = await req.json();

// Process webhook... await supabase.from('processed').insert({ data: record });

return new Response(JSON.stringify({ success: true }), { headers: { 'Content-Type': 'application/json' }, }); });

Storage with Policies

-- Create bucket INSERT INTO storage.buckets (id, name, public) VALUES ('avatars', 'avatars', true);

-- Storage policies CREATE POLICY "Users can upload own avatar" ON storage.objects FOR INSERT WITH CHECK ( bucket_id = 'avatars' AND auth.uid()::text = (storage.foldername(name))[1] );

CREATE POLICY "Anyone can view avatars" ON storage.objects FOR SELECT USING (bucket_id = 'avatars');

// Upload file const { data, error } = await supabase.storage .from('avatars') .upload(${userId}/avatar.png, file, { cacheControl: '3600', upsert: true, });

// Get public URL const { data: { publicUrl } } = supabase.storage .from('avatars') .getPublicUrl(${userId}/avatar.png);

Next.js Server Components

// app/api/posts/route.ts import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers';

export async function GET() { const supabase = createRouteHandlerClient({ cookies }); const { data: posts } = await supabase.from('posts').select('*'); return Response.json(posts); }

// Server Component import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers';

export default async function Page() { const supabase = createServerComponentClient({ cookies }); const { data: posts } = await supabase.from('posts').select('*'); return <PostList posts={posts} />; }

Use Cases

  • Building SaaS applications with multi-tenant RLS

  • Real-time collaborative applications

  • Mobile app backends with authentication

  • Serverless APIs with Edge Functions

  • File upload systems with access control

Best Practices

Do Avoid

Enable RLS on all tables Disabling RLS "temporarily" in production

Use auth.uid() in policies, not session data Trusting client-side user ID

Create service role client only server-side Exposing service role key to client

Use TypeScript types from supabase gen types

Manual type definitions

Filter subscriptions to reduce bandwidth Subscribing to entire tables

Use supabase db push for dev, migrations for prod Pushing directly to production

Set up proper bucket policies Public buckets for sensitive files

Use signInWithOAuth for social auth Custom OAuth implementations

CLI Commands

Local development

supabase start # Start local Supabase supabase db reset # Reset with migrations + seed

Migrations

supabase migration new add_posts # Create migration supabase db push # Push to linked project (dev only) supabase db diff --use-migra # Generate migration from diff

Type generation

supabase gen types typescript --local > types/supabase.ts

Edge Functions

supabase functions serve # Local development supabase functions deploy my-func # Deploy to production

Related Skills

See also these related skill documents:

  • designing-database-schemas - Schema design patterns

  • managing-database-migrations - Migration strategies

  • implementing-oauth - OAuth flow details

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

database-optimization

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

postgresql

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

real-time-systems

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

docker

No summary provided by upstream source.

Repository SourceNeeds Review