supabase-patterns
Generic Supabase best practices for Row Level Security, realtime subscriptions, storage, and edge functions. Framework-agnostic.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Generic Supabase best practices for Row Level Security, realtime subscriptions, storage, and edge functions. Framework-agnostic.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Generic BAML patterns for type-safe LLM prompting. Covers schema design, DTO generation, client wrappers, and cross-language codegen. Framework-agnostic.
Browser automation for documentation discovery. Use when curl fails on JS-rendered sites, when detecting available browser tools, or when configuring browser-based documentation collection.
C4 architectural modeling for documenting software architecture. Use when creating architecture diagrams, planning new systems, communicating with stakeholders, or conducting architecture reviews.
Debug and analyze web applications using Chrome DevTools MCP. Use for console log inspection, network request monitoring, performance analysis, and debugging authenticated sessions. For basic browser automation (screenshots, form filling), use browser-discovery skill instead.
Patterns and techniques for analyzing brownfield codebases. Use when onboarding to unfamiliar code, preparing for refactoring, conducting architecture reviews, or identifying technical debt.
Detect new imports in modified files and auto-install missing dependencies. Works with npm, uv, pip, cargo, go mod, and other package managers. Triggers after code implementation to keep manifests in sync.
| name | supabase-patterns |
| description | Generic Supabase best practices for Row Level Security, realtime subscriptions, storage, and edge functions. Framework-agnostic. |
Universal patterns for working with Supabase in any project. Covers RLS policies, realtime, storage, edge functions, and migrations.
This skill is framework-generic. It provides universal Supabase patterns:
| Variable | Default | Description |
|---|---|---|
| SUPABASE_DIR | supabase | Directory for Supabase config |
| ENFORCE_RLS | true | Require RLS on all tables |
| REALTIME_ENABLED | auto | Auto-detect realtime tables |
MANDATORY - Follow the Workflow steps below in order.
If you're about to:
STOP -> Add RLS policies -> Use appropriate keys -> Then proceed
./cookbook/rls-policies.md./cookbook/realtime-subscriptions.md./cookbook/storage-patterns.mdsupabase/
├── config.toml # Project config
├── migrations/ # SQL migrations
│ ├── 20231201000000_initial.sql
│ └── 20231202000000_add_users.sql
├── seed.sql # Seed data
└── functions/ # Edge functions
└── hello/
└── index.ts
# Initialize project
supabase init
# Start local development
supabase start
# Generate migration
supabase migration new my_migration
# Push to remote
supabase db push
# Generate types
supabase gen types typescript --local > types/supabase.ts
-- Enable RLS
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
-- User owns row
CREATE POLICY "Users can view own posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);
-- User can insert own
CREATE POLICY "Users can create posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Public read
CREATE POLICY "Public read"
ON posts FOR SELECT
USING (is_public = true);
// Initialize client
import { createClient } from '@supabase/supabase-js';
import type { Database } from './types/supabase';
const supabase = createClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_ANON_KEY!
);
// Query with types
const { data, error } = await supabase
.from('posts')
.select('*')
.eq('user_id', userId);
// Insert
const { data, error } = await supabase
.from('posts')
.insert({ title, content, user_id: userId })
.select()
.single();
// Subscribe to changes
const subscription = supabase
.channel('posts')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'posts' },
(payload) => {
console.log('Change:', payload);
}
)
.subscribe();
// Cleanup
subscription.unsubscribe();
// Upload file
const { data, error } = await supabase.storage
.from('avatars')
.upload(`${userId}/avatar.png`, file, {
upsert: true,
contentType: 'image/png'
});
// Get public URL
const { data: { publicUrl } } = supabase.storage
.from('avatars')
.getPublicUrl(`${userId}/avatar.png`);
Supabase migrations should align with ORM models:
-- supabase/migrations/20231201000000_users.sql
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email TEXT UNIQUE NOT NULL,
name TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
Should match:
# SQLAlchemy model
class User(Base):
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
email: Mapped[str] = mapped_column(unique=True)
name: Mapped[str | None]
created_at: Mapped[datetime] = mapped_column(server_default=func.now())
# Generate TypeScript types from local schema
supabase gen types typescript --local > types/supabase.ts
# Use in client
import type { Database } from './types/supabase';
type Post = Database['public']['Tables']['posts']['Row'];