/supabase

Supabase tables with migrations, grants, RLS, typed clients and denied-access tests.

Build·Data → Product·45 installs·MIT
$npx skills add tushaarmehtaa/tushar-skills --skill supabase -g -a claude-code -y

Then type /supabase in Claude Code, or describe the task and let it pick the skill.

What you get back contract tests · 9 Oct 2026

claude · tallyroom

Using /supabase
  • 36 access-rule tests pass
  • Magic-link sign-in added
  • Nothing pushed to remote
The dashboard reads real flats from Supabase, and you only see your own.
Claude Code 2.1.295·5m 31s·14 files changed
  • The dashboard now reads real flats, members and expenses from Supabase, and each signed-in user only sees the flats they belong to. Nothing has been pushed to the remote project, and nothing is committed.
  • Verification. Docker isn't installed, so I couldn't run Supabase's local stack. Instead I applied the migration to a scratch Postgres 16 with a minimal stand-in for Supabase's auth schema and roles. My 36 access-rule tests (supabase/tests/rls_test.sql) all pass there, the build passes, and signed-out visitors to /dashboard are redirected to /login.
  • Nobody can move an expense to another flat, promote themselves to owner, or pose as another user. The tests cover each of these, plus other users and people in no flat.
CaveatRan with test keys; the dashboard's queries never reached a real Supabase API.

Input → output from the run

app/dashboard/page.jsx before
const expenses = [
  { date: "Oct 1", what: "Groceries — Nature's Basket", paidBy: "Arjun", amount: 2840.5, split: "4 ways", status: "Unsettled" },
  { date: "Sep 30", what: "Electricity bill (Sept)", paidBy: "Maya", amount: 3125, split: "4 ways", status: "Settled" },
  { date: "Sep 28", what: "Wi-Fi — ACT Fibernet", paidBy: "Kabir", amount: 1179, split: "4 ways", status: "Unsettled" },
  { date: "Sep 27", what: "Dinner at Toit", paidBy: "Arjun", amount: 4620, split: "3 ways", status: "Unsettled" },
  { date: "Sep 25", what: "Cooking gas refill", paidBy: "Neha", amount: 903, split: "4 ways", status: "Settled" },
];

export default function Dashboard() {
  const total = expenses.reduce((s, e) => s + e.amount, 0);
app/dashboard/page.jsx after
export default async function Dashboard({ searchParams }) {
  const supabase = await createClient();
  const { data: auth } = await supabase.auth.getClaims();
  const userId = auth?.claims?.sub;
  if (!userId) redirect("/login");

  // RLS limits every query below to flats this user belongs to.
  const { data: memberships, error: membershipsError } = await supabase
    .from("group_members")
    .select("id, group_id, groups(name)")
    .eq("user_id", userId)
    .order("created_at");
  if (membershipsError) throw new Error(`Couldn't load your flats: ${membershipsError.message}`);

When to use it

Use when

Use when integrating Supabase or repairing data access and tenant isolation.

Skip it when

Skip it if you are not on Supabase, or want the same four CRUD policies stamped on every table.

The thinking behind it

Most Supabase bugs are access bugs. Get tables, policies and typed clients right from the start, and every user only ever sees their own data.

Output contract from the skill's Output section

Report tables/functions/storage changed, migration files, grants and RLS policies with auth strategy, client/session changes, type-generation command/result, negative authorization tests, and remaining linked-project/dashboard/production steps.

How it checks its own work from the instructions

  • Local migrations reset and apply cleanly
  • Schema and generated types show no drift
  • Anonymous, other-user, and other-tenant access is denied
  • Attempts to change row ownership are tested

Requirements what it needs

Works in
Codex, Claude Code, Cursor
Needs
project files, terminal commands, network access

The instructions SKILL.md · 32 lines

Instructions & references

Back to overview ↑
On this page 4 sections
SKILL.md · MIT

Supabase

Build a migration-backed, typed Supabase integration with explicit authorization boundaries.

Workflow

  1. Inspect supabase/, migrations, generated types, installed Supabase packages/versions, framework/runtime, environment-variable names without printing values, auth/session flow, schemas exposed through the Data API, and existing grants/RLS.
  2. Infer table ownership and tenant relationships from the domain model. Ask only when ownership, collaboration, deletion, retention, or external-auth behavior is ambiguous. Do not add user_id or four CRUD policies to every table mechanically.
  3. Design keys, foreign keys, constraints, indexes, timestamps, lifecycle/deletion behavior, and server-generated ownership defaults appropriate to each table. Use external provider subject IDs as text unless a local identity mapping is intentionally modeled.
  4. Create named migrations. Use supabase migration new or a reviewed db diff for local changes, verify with a local reset/test database, inspect db push --dry-run, and use db push only when remote deployment is explicitly in scope. migration up is not a substitute for remote deployment.
  5. Secure every exposed object with both Postgres grants and RLS. Scope policies to roles, use indexed predicates, add with check for inserts/updates, review views/functions separately, and set a safe search_path on security definer functions.
  6. Match auth strategy:
    • Supabase Auth: use auth.uid()/auth.jwt() and current SSR session guidance.
    • Clerk or another supported third-party provider: configure the native integration, pass the provider token through the client, and use the actual JWT sub/claims. Do not assume an RLS expression alone configures token verification.
    • Server administration: use a dedicated server-only client with explicit authorization; never expose secret/service credentials.
  7. For current @supabase/ssr, create a client per request, use the supported cookie getAll/setAll adapter, await async framework cookie APIs, and add the required proxy/middleware refresh flow. Do not use legacy single-cookie adapters.
  8. Generate TypeScript types after applying migrations to the target used for generation, then run type checks and update typed queries. Avoid any and handle { data, error } explicitly.

Verification

Run local migration reset/apply, schema/type drift checks, and repository lint/type/test/build. For each policy, test allowed owner/member/admin/service access and denied anonymous/other-user/other-tenant reads and mutations, including attempts to change ownership. Test session refresh/expiry and external-provider tokens in the target runtime.

Output

Report tables/functions/storage changed, migration files, grants and RLS policies with auth strategy, client/session changes, type-generation command/result, negative authorization tests, and remaining linked-project/dashboard/production steps.

View on GitHub ↗
Claude app, ChatGPT and ZIP download

local coding agent required

This skill requires project files, terminal commands, and network access. Uploading it to a chat app does not provide equivalent execution.

ChatGPT Skills

This workflow needs a local coding environment or capabilities that a chat-only Skills upload does not provide.

Package details
Package
supabase/SKILL.md
Author
@tushaarmehtaa
Added
16 Jun 2026
Tags
supabasepostgresrlsauthmigrationstypescript