Agent skill
supabase-mastery
Master Supabase patterns for migrations, RLS policies, pgvector, and authentication. Use when creating database schemas, writing migrations, implementing row-level security, setting up auth, or debugging Supabase issues. Triggers on "supabase migration", "RLS policy", "row level security", "pgvector", "supabase auth", "magic link".
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/supabase-mastery
SKILL.md
Supabase Mastery for Scientia Stack
Patterns from 18 production Supabase projects.
Migration Workflow
Creating Migrations
# Create timestamped migration
supabase migration new feature_name
# This creates: supabase/migrations/YYYYMMDDHHMMSS_feature_name.sql
Migration File Structure
-- supabase/migrations/001_initial_schema.sql
-- Create tables
CREATE TABLE IF NOT EXISTS posts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
sentiment TEXT CHECK (sentiment IN ('bullish', 'bearish', 'neutral')),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Create indexes
CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- Create RLS policies
CREATE POLICY "Users can view own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);
CREATE POLICY "Users can insert own posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own posts"
ON posts FOR UPDATE
USING (auth.uid() = user_id);
CREATE POLICY "Users can delete own posts"
ON posts FOR DELETE
USING (auth.uid() = user_id);
Running Migrations
# Apply to local
supabase db reset
# Apply to remote
supabase db push
# Check status
supabase migration list
Row Level Security (RLS) Patterns
Pattern 1: User Isolation
-- Users can only access their own data
CREATE POLICY "user_isolation"
ON table_name
FOR ALL
USING (auth.uid() = user_id);
Pattern 2: Public Read, Private Write
-- Anyone can read, only owner can write
CREATE POLICY "public_read"
ON posts FOR SELECT
USING (true);
CREATE POLICY "owner_write"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
Pattern 3: Tier-Based Access
-- Based on user subscription tier
CREATE POLICY "tier_based_access"
ON premium_features
FOR SELECT
USING (
EXISTS (
SELECT 1 FROM user_subscriptions
WHERE user_id = auth.uid()
AND tier IN ('pro', 'premium', 'enterprise')
AND expires_at > NOW()
)
);
Pattern 4: Service Role Bypass
-- Allow service role to bypass RLS (for backend)
CREATE POLICY "service_role_bypass"
ON table_name
FOR ALL
TO service_role
USING (true);
pgvector for RAG
Enable Extension
CREATE EXTENSION IF NOT EXISTS vector;
Create Embeddings Table
CREATE TABLE documents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
content TEXT NOT NULL,
embedding VECTOR(1536), -- OpenAI dimensions (but we don't use OpenAI!)
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Create index for similarity search
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
Similarity Search Function
CREATE OR REPLACE FUNCTION match_documents(
query_embedding VECTOR(1536),
match_threshold FLOAT DEFAULT 0.7,
match_count INT DEFAULT 5
)
RETURNS TABLE (
id UUID,
content TEXT,
similarity FLOAT
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
d.id,
d.content,
1 - (d.embedding <=> query_embedding) AS similarity
FROM documents d
WHERE 1 - (d.embedding <=> query_embedding) > match_threshold
ORDER BY d.embedding <=> query_embedding
LIMIT match_count;
END;
$$;
Authentication Patterns
Magic Link (Email + Phone)
Configure in Supabase Dashboard:
- Authentication → Providers → Email
- Enable "Confirm email" and "Secure email change"
- Set redirect URLs:
https://your-app.vercel.app/feedhttps://your-app.vercel.app
Frontend Implementation
import { createClient } from '@supabase/supabase-js'
const supabase = createClient(
process.env.VITE_SUPABASE_URL!,
process.env.VITE_SUPABASE_ANON_KEY!
)
// Send magic link
const { error } = await supabase.auth.signInWithOtp({
email: 'user@example.com',
options: {
emailRedirectTo: `${window.location.origin}/feed`
}
})
// Check session
const { data: { session } } = await supabase.auth.getSession()
Backend Service Role
from supabase import create_client
supabase = create_client(
os.environ["SUPABASE_URL"],
os.environ["SUPABASE_SERVICE_KEY"] # Service role for backend
)
# Service role bypasses RLS
data = supabase.table("posts").select("*").execute()
Common Patterns
JSONB for Flexible Data
CREATE TABLE user_settings (
user_id UUID PRIMARY KEY REFERENCES auth.users(id),
preferences JSONB DEFAULT '{
"theme": "dark",
"notifications": true,
"language": "en"
}'::JSONB,
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Query JSONB
SELECT * FROM user_settings
WHERE preferences->>'theme' = 'dark';
Auto-Update Timestamps
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER update_posts_updated_at
BEFORE UPDATE ON posts
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();
Soft Deletes
ALTER TABLE posts ADD COLUMN deleted_at TIMESTAMPTZ;
-- Update RLS to filter deleted
CREATE POLICY "hide_deleted"
ON posts FOR SELECT
USING (deleted_at IS NULL AND auth.uid() = user_id);
Debugging
Check RLS Policies
SELECT schemaname, tablename, policyname, permissive, roles, cmd, qual
FROM pg_policies
WHERE tablename = 'your_table';
Test as User
-- Set role to test RLS
SET ROLE authenticated;
SET request.jwt.claim.sub = 'user-uuid-here';
-- Run query
SELECT * FROM posts;
-- Reset
RESET ROLE;
Common Issues
-
"new row violates row-level security policy"
- Check INSERT policy
WITH CHECKclause - Ensure
auth.uid()matches user_id
- Check INSERT policy
-
Empty results despite data existing
- RLS blocking access
- Check SELECT policy
USINGclause
-
Service role not working
- Ensure using
SUPABASE_SERVICE_KEYnotANON_KEY - Check service role policy exists
- Ensure using
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?