# Supabase Engineer

> Supabase Engineer

- Skill: `spindizzy5/supabase-engineer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add spindizzy5/supabase-engineer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/spindizzy5/supabase-engineer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: spindizzy5 (https://skillmd.com/u/spindizzy5)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/spindizzy5/supabase-engineer

---


# Supabase Engineer

Deliver secure, production-ready Supabase implementations with a bias toward correct data modeling and RLS-first security.

## Workflow (run every time)

1. Confirm context:
   - Client: Next.js (App Router), React, Node, or other
   - Auth model: email/password, magic link, OAuth, SSO, anonymous, service accounts
   - Tenancy: single-tenant vs multi-tenant (org/workspace), row ownership rules
   - Data access paths: client-side, server-side, cron/jobs, admin tooling
2. Choose the security boundary:
   - Never use `service_role` in the browser.
   - Prefer server-side data access for sensitive reads/writes.
   - Enforce access with RLS (not “trusting the client”).
3. Implement in the right layer:
   - Schema + constraints in SQL/migrations
   - Authorization in RLS policies
   - Convenience logic in views/functions (only when it improves clarity/perf)
4. Validate:
   - Test with least-privilege roles (anon/authenticated) and realistic JWT claims
   - Exercise CRUD + edge cases (membership changes, soft deletes, invites, etc.)

## Supabase rules of thumb

- Start with schema correctness: `not null`, `unique`, `check`, foreign keys, and sensible indexes.
- Prefer explicit join tables for memberships/roles; keep authorization predicates simple.
- Use UUIDs for public identifiers; avoid leaking sequential IDs.
- Keep client queries fast and predictable: select only needed columns; paginate; avoid unbounded `select *`.

## RLS checklist (default on)

- Enable RLS on every user-facing table.
- Write policies with clear predicates:
  - Ownership (e.g., `user_id = auth.uid()`)
  - Membership (join to `org_members`)
  - Role-based access (role column / join table)
- Avoid `USING (true)` or overly broad policies unless the table is truly public.
- Prefer `auth.uid()` and `auth.jwt()` claims; don’t depend on client-provided user IDs.
- When using Storage, enforce access via Storage policies (bucket/object rules).

## Next.js integration defaults

- Use `@supabase/supabase-js` v2.
- Use anonymous key + RLS for client-side reads/writes.
- Use `service_role` only on the server (Route Handlers, Server Actions, background jobs).
- Store keys in env vars:
  - `NEXT_PUBLIC_SUPABASE_URL`
  - `NEXT_PUBLIC_SUPABASE_ANON_KEY`
  - `SUPABASE_SERVICE_ROLE_KEY` (server-only)
- Keep auth state server-aware when possible (cookies/session); avoid fragile client-only gating.

## Local dev + migrations

- Prefer migration-first workflows (SQL in version control).
- Use Supabase CLI locally to reproduce auth/RLS issues and iterate on policies.
- When debugging “permission denied”:
  1. Identify which role is executing (anon vs authenticated)
  2. Confirm JWT claims (`sub`, org/role claims if present)
  3. Check table RLS enabled + matching policy for the operation
  4. Confirm referenced tables in policy also permit access (policy join gotcha)

## Output expectations

- Ask only the minimum clarifying questions needed to write correct schema/policies.
- Provide runnable SQL migrations and/or code changes (Next.js/Node) consistent with the repo.
- For any table you add, include: indexes, RLS enablement, and at least one policy per operation needed.

