Skill: dev-supabase
Backend development with Supabase. Trigger when the user wants to configure auth, the database, or Supabase storage.
Configuration
| Property | Value |
|---|---|
| Context | inline |
| Pre-approved tools | None declared: the project's permission settings apply |
| Trigger | keywords: dev, supabase, supabase — |
Detailed description
Supabase (pointer)
Supabase publishes the canonical agent skills at supabase/agent-skills — maintained by the Supabase team, in sync with current API (Auth, DB, Edge Functions, Realtime, Storage). The repo ships two skills that stay current with every API release; the prior foundation skill (224 lines) drifted on each Supabase version.
Delegate to the vendor skills
# Vendor publishes via marketplace (verify on their README):
claude plugin install supabase@supabase
# Fallback — clone and symlink both skills:
git clone --depth 1 https://github.com/supabase/agent-skills ~/dev/vendor-skills/supabase
ln -s ~/dev/vendor-skills/supabase/skills/supabase ./.claude/skills/supabase
ln -s ~/dev/vendor-skills/supabase/skills/supabase-postgres-best-practices \
./.claude/skills/supabase-postgres-best-practices
supabase— Auth, DB, Edge Functions, Realtime, Storage with current API patterns.supabase-postgres-best-practices— 30 rules across 8 categories (indexing, RLS perf, schema design, pg_* extensions).
Recipe entry: docs/recipes/recommended-vendor-skills.md §"Supabase — supabase/agent-skills". Reduction rationale: specs/foundation-positioning-review/spec.md Wave 1.
Foundation-unique angle preserved: cross-cutting discipline
The vendor covers the Supabase API surface. The foundation enforces version-agnostic conventions that survive across releases:
- Auth: Supabase Auth is one option among many — cross-ref the
dev-authskill for framework-agnostic patterns (sessions, OAuth, magic links) before deciding on Supabase-specific flows. - ORM interop: Prisma operates against the same Postgres, and Supabase RLS coexists with Prisma queries — cross-ref the
dev-prismaskill. - General Postgres: the vendor's
supabase-postgres-best-practicesskill is useful for any Postgres project, not just Supabase-managed — cross-ref theops-databaseskill. - Security: RLS on every public table,
service_rolekey server-side only —.claude/rules/supabase.md(below) and.claude/rules/security.md.
Foundation rules: .claude/rules/supabase.md
The RLS, service_role, secret and query rules this pointer used to carry live in .claude/rules/supabase.md, scoped to the Supabase files. Installed next to the vendor's skills, only one side fires (measured 2026-10-03: Supabase's own skill alone 3/3; Prisma's pointer used to win 3/3 until its description stepped aside, now prisma-cli fires 3/3), so a rule kept in a skill reaches the session only when that skill wins — a rule loaded by the files holds whichever skill fires.
Automatic triggering
This skill is automatically activated when:
- The matching keywords are detected in the conversation
- The task context matches the skill's domain
Triggering examples
- "I want to dev..."
- "I want to supabase..."
- "I want to supabase — ..."
Context inline
Inline means the skill runs in the conversation (the default, no context key):
- Sees the full history
- Its work is visible as it happens
- Right for almost every skill
Practical examples
1. Example: Supabase Auth + Row Level Security
Example: Supabase Auth + Row Level Security
Scenario
A multi-tenant task management app where users can only see their own tasks and team-shared tasks.
Database Schema
-- Create tables
CREATE TABLE profiles (
id UUID REFERENCES auth.users(id) PRIMARY KEY,
team_id UUID REFERENCES teams(id),
display_name TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('admin', 'member'))
);
CREATE TABLE tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title TEXT NOT NULL,
completed BOOLEAN DEFAULT false,
owner_id UUID REFERENCES auth.users(id) NOT NULL,
team_id UUID REFERENCES teams(id),
created_at TIMESTAMPTZ DEFAULT now()
);
Row Level Security Policies
-- Enable RLS
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
-- Users can read their own tasks + team tasks
CREATE POLICY "Users can view own and team tasks"
ON tasks FOR SELECT
USING (
owner_id = auth.uid()
OR team_id IN (
SELECT team_id FROM profiles WHERE id = auth.uid()
)
);
-- Users can only insert tasks they own
CREATE POLICY "Users can create own tasks"
ON tasks FOR INSERT
WITH CHECK (owner_id = auth.uid());
-- Users can update only their own tasks
CREATE POLICY "Users can update own tasks"
ON tasks FOR UPDATE
USING (owner_id = auth.uid());
-- Admins can delete any team task
CREATE POLICY "Admins can delete team tasks"
ON tasks FOR DELETE
USING (
owner_id = auth.uid()
OR EXISTS (
SELECT 1 FROM profiles
WHERE id = auth.uid() AND role = 'admin'
AND team_id = tasks.team_id
)
);
Client Usage (TypeScript)
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
// Sign up - profile created via trigger
const { data } = await supabase.auth.signUp({
email: 'user@example.com',
password: 'securepassword123',
});
// Fetch tasks - RLS automatically filters to user's own + team tasks
const { data: tasks } = await supabase
.from('tasks')
.select('id, title, completed, owner_id')
.order('created_at', { ascending: false });
// Insert task - RLS ensures owner_id matches auth.uid()
const { error } = await supabase
.from('tasks')
.insert({ title: 'New task', owner_id: user.id, team_id: user.team_id });
Key Decisions
- RLS over application-level filtering: Security enforced at database level, not bypassable
auth.uid()function: Built-in Supabase function, no need to pass user ID manually- Team visibility: Users see team tasks via profile lookup, not task-level ACL
- Role-based delete: Only admins can delete others' tasks within their team
- Anon key on client: Safe because RLS restricts all access by authenticated user