/supabase
Core Supabase CLI, migrations, RLS, Edge Functions
$ npx -y skills add alinaqi/maggy --skill supabase --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/supabase
Context preview
The summary Claude sees to decide when to auto-load this skill.
Core Supabase CLI, migrations, RLS, Edge Functions
SKILL.md
supabase.SKILL.mdname: supabase
description: Core Supabase CLI, migrations, RLS, Edge Functions
when-to-use: When working with Supabase - database, auth, storage, or edge functions
user-invocable: false
paths: ["supabase/**", "**/supabase.*", "**/.env*"]
effort: medium
Supabase Core Skill
Core concepts, CLI workflow, and patterns common to all Supabase projects.
**Sources:** [Supabase Docs](https://supabase.com/docs) | [Supabase CLI](https://supabase.com/docs/guides/local-development/cli/getting-started)
---
Core Principle
**Local-first, migrations in version control, never touch production directly.**
Develop locally with the Supabase CLI, capture all changes as migrations, and deploy through CI/CD.
---
Supabase Stack
| Service | Purpose | |---------|---------| | **Database** | PostgreSQL with extensions | | **Auth** | User authentication, OAuth providers | | **Storage** | File storage with RLS | | **Edge Functions** | Serverless Deno functions | | **Realtime** | WebSocket subscriptions | | **Vector** | AI embeddings (pgvector) |
---
CLI Setup
Install & Login
# macOS
brew install supabase/tap/supabase
# npm (alternative)
npm install -g supabase
# Login
supabase login
Initialize Project
# In your project directory
supabase init
# Creates:
# supabase/
# ├── config.toml # Local config
# ├── seed.sql # Seed data
# └── migrations/ # SQL migrations
Link to Remote
# Get project ref from dashboard URL: https://supabase.com/dashboard/project/<ref>
supabase link --project-ref <project-id>
# Pull existing schema
supabase db pull
Start Local Stack
supabase start
# Output:
# API URL: http://localhost:54321
# GraphQL URL: http://localhost:54321/graphql/v1
# DB URL: postgresql://postgres:postgres@localhost:54322/postgres
# Studio URL: http://localhost:54323
# Anon key: eyJ...
# Service role key: eyJ...
---
Migration Workflow
Option 1: Dashboard + Diff (Quick Prototyping)
# 1. Make changes in local Studio (localhost:54323)
# 2. Generate migration from diff
supabase db diff -f <migration_name>
# 3. Review generated SQL
cat supabase/migrations/*_<migration_name>.sql
# 4. Reset to test
supabase db reset
Option 2: Write Migrations Directly (Recommended)
# 1. Create empty migration
supabase migration new create_users_table
# 2. Edit the migration file
# supabase/migrations/<timestamp>_create_users_table.sql
# 3. Apply locally
supabase db reset
Option 3: ORM Migrations (Best DX)
Use Drizzle (TypeScript) or SQLAlchemy (Python) - see framework-specific skills.
Deploy Migrations
# Push to remote (staging/production)
supabase db push
# Check migration status
supabase migration list
---
Database Patterns
Enable RLS on All Tables
-- Always enable RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
-- Default deny - must create policies
CREATE POLICY "Users can view own profile"
ON public.profiles
FOR SELECT
USING (auth.uid() = id);
Common RLS Policies
-- Public read
CREATE POLICY "Public read access"
ON public.posts FOR SELECT
USING (true);
-- Authenticated users only
CREATE POLICY "Authenticated users can insert"
ON public.posts FOR INSERT
WITH CHECK (auth.role() = 'authenticated');
-- Owner access
CREATE POLICY "Users can update own records"
ON public.posts FOR UPDATE
USING (auth.uid() = user_id);
-- Admin access (using custom claim)
CREATE POLICY "Admins have full access"
ON public.posts FOR ALL
USING (auth.jwt() ->> 'role' = 'admin');
Link to auth.users
-- Profile table linked to auth
CREATE TABLE public.profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
username TEXT UNIQUE NOT NULL,
avatar_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Auto-create profile on signup
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, username)
VALUES (NEW.id, NEW.email);
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
---
Seed Data
supabase/seed.sql
-- Runs on `supabase db reset`
-- Use ON CONFLICT for idempotency
INSERT INTO public.profiles (id, username, avatar_url)
VALUES
('d0e1f2a3-b4c5-6d7e-8f9a-0b1c2d3e4f5a', 'testuser', null),
('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', 'admin', null)
ON CONFLICT (id) DO NOTHING;---
Environment Variables
Required Variables
# Public (safe for client-side)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=eyJ...
# Private (server-side only - NEVER expose)
SUPABASE_SERVICE_ROLE_KEY=eyJ...
DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-region.pooler.supabase.com:6543/postgres
Local vs Production
# .env.local (local development)
SUPABASE_URL=http://localhost:54321
SUPABASE_ANON_KEY=<from supabase start>
DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres
# .env.production (remote)
SUPABASE_URL=https://xxxxx.supabase.co
SUPABASE_ANON_KEY=<from dashboard>
DATABASE_URL=<connection pooler URL>
Connection Pooling
# Transaction mode (recommended for serverless)
# Add ?pgbouncer=true to URL
DATABASE_URL=postgresql://...@pooler.supabase.com:6543/postgres?pgbouncer=true
# Session mode (for migrations, long transactions)
DATABASE_URL=postgresql://...@pooler.supabase.com:5432/postgres
---
Edge Functions
Create Function
supabase functions new hello-world
Basic Structure
// supabase/functions/hello-world/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
serve(async (req) => {
const { name } = await req.json();
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { 'Content-Type': 'application/Read more
name: supabase description: Core Supabase CLI, migrations, RLS, Edge Functions when-to-use: When working with Supabase - database, auth, storage, or edge functions user-invocable: false paths: ["supabase/**", "**/supabase.*", "**/.env*"] effort: medium
Supabase Core Skill
Core concepts, CLI workflow, and patterns common to all Supabase projects.
**Sources:** [Supabase Docs](https://supabase.com/docs) | [Supabase CLI](https://supabase.com/docs/guides/local-development/cli/getting-started)
---
Core Principle
**Local-first, migrations in version control, never touch production directly.**
Develop locally with the Supabase CLI, capture all changes as migrations, and deploy through CI/CD.
---
Supabase Stack
| Service | Purpose | |---------|---------| | **Database** | PostgreSQL with extensions | | **Auth** | User authentication, OAuth providers | | **Storage** | File storage with RLS | | **Edge Functions** | Serverless Deno functions | | **Realtime** | WebSocket subscriptions | | **Vector** | AI embeddings (pgvector) |
---
CLI Setup
Install & Login
# macOS brew install supabase/tap/supabase # npm (alternative) npm install -g supabase # Login supabase login
Initialize Project
# In your project directory supabase init # Creates: # supabase/ # ├── config.toml # Local config # ├── seed.sql # Seed data # └── migrations/ # SQL migrations
Link to Remote
# Get project ref from dashboard URL: https://supabase.com/dashboard/project/<ref> supabase link --project-ref <project-id> # Pull existing schema supabase db pull
Start Local Stack
supabase start # Output: # API URL: http://localhost:54321 # GraphQL URL: http://localhost:54321/graphql/v1 # DB URL: postgresql://postgres:postgres@localhost:54322/postgres # Studio URL: http://localhost:54323 # Anon key: eyJ... # Service role key: eyJ...
---
Migration Workflow
Option 1: Dashboard + Diff (Quick Prototyping)
# 1. Make changes in local Studio (localhost:54323) # 2. Generate migration from diff supabase db diff -f <migration_name> # 3. Review generated SQL cat supabase/migrations/*_<migration_name>.sql # 4. Reset to test supabase db reset
Option 2: Write Migrations Directly (Recommended)
# 1. Create empty migration supabase migration new create_users_table # 2. Edit the migration file # supabase/migrations/<timestamp>_create_users_table.sql # 3. Apply locally supabase db reset
Option 3: ORM Migrations (Best DX)
Use Drizzle (TypeScript) or SQLAlchemy (Python) - see framework-specific skills.
Deploy Migrations
# Push to remote (staging/production) supabase db push # Check migration status supabase migration list
---
Database Patterns
Enable RLS on All Tables
-- Always enable RLS ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY; -- Default deny - must create policies CREATE POLICY "Users can view own profile" ON public.profiles FOR SELECT USING (auth.uid() = id);
Common RLS Policies
-- Public read CREATE POLICY "Public read access" ON public.posts FOR SELECT USING (true); -- Authenticated users only CREATE POLICY "Authenticated users can insert" ON public.posts FOR INSERT WITH CHECK (auth.role() = 'authenticated'); -- Owner access CREATE POLICY "Users can update own records" ON public.posts FOR UPDATE USING (auth.uid() = user_id); -- Admin access (using custom claim) CREATE POLICY "Admins have full access" ON public.posts FOR ALL USING (auth.jwt() ->> 'role' = 'admin');
Link to auth.users
-- Profile table linked to auth CREATE TABLE public.profiles ( id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, username TEXT UNIQUE NOT NULL, avatar_url TEXT, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Auto-create profile on signup CREATE OR REPLACE FUNCTION public.handle_new_user() RETURNS TRIGGER AS $$ BEGIN INSERT INTO public.profiles (id, username) VALUES (NEW.id, NEW.email); RETURN NEW; END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
---
Seed Data
supabase/seed.sql
-- Runs on `supabase db reset`
-- Use ON CONFLICT for idempotency
INSERT INTO public.profiles (id, username, avatar_url)
VALUES
('d0e1f2a3-b4c5-6d7e-8f9a-0b1c2d3e4f5a', 'testuser', null),
('a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d', 'admin', null)
ON CONFLICT (id) DO NOTHING;---
Environment Variables
Required Variables
# Public (safe for client-side) SUPABASE_URL=https://xxxxx.supabase.co SUPABASE_ANON_KEY=eyJ... # Private (server-side only - NEVER expose) SUPABASE_SERVICE_ROLE_KEY=eyJ... DATABASE_URL=postgresql://postgres.[ref]:[password]@aws-0-region.pooler.supabase.com:6543/postgres
Local vs Production
# .env.local (local development) SUPABASE_URL=http://localhost:54321 SUPABASE_ANON_KEY=<from supabase start> DATABASE_URL=postgresql://postgres:postgres@localhost:54322/postgres # .env.production (remote) SUPABASE_URL=https://xxxxx.supabase.co SUPABASE_ANON_KEY=<from dashboard> DATABASE_URL=<connection pooler URL>
Connection Pooling
# Transaction mode (recommended for serverless) # Add ?pgbouncer=true to URL DATABASE_URL=postgresql://...@pooler.supabase.com:6543/postgres?pgbouncer=true # Session mode (for migrations, long transactions) DATABASE_URL=postgresql://...@pooler.supabase.com:5432/postgres
---
Edge Functions
Create Function
supabase functions new hello-world
Basic Structure
// supabase/functions/hello-world/index.ts
import { serve } from 'https://deno.land/std@0.168.0/http/server.ts';
serve(async (req) => {
const { name } = await req.json();
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { 'Content-Type': 'application/Turn Claude Code into a self-reviewing, test-enforced engineering system that remembers context across sessions — then route work across 13 models from a single dashboard.
Repo: alinaqi/maggy
Other skills on maggy.
- /aeo-optimization
AI Engine Optimization - semantic triples, page templates, content clusters for AI citations
Open skill - /agent-teams
Claude Code Agent Teams - default team-based development with strict TDD pipeline enforcement
Open skill - /agentic-development
Build AI agents with Pydantic AI (Python) and Claude SDK (Node.js)
Open skill - /ai-models
Latest AI models reference - Claude, OpenAI, Gemini, Eleven Labs, Replicate
Open skill - /android-java
Android Java development with MVVM, ViewBinding, and Espresso testing
Open skill - /android-kotlin
Android Kotlin development with Coroutines, Jetpack Compose, Hilt, and MockK testing
Open skill

