SU

supabase-known-pitfalls

Identifies common Supabase mistakes like missing RLS, service role exposure, and improper error handling.

Install

mkdir -p .claude/skills/supabase-known-pitfalls && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/7425" && unzip -o skill.zip -d .claude/skills/supabase-known-pitfalls && rm skill.zip

Installs to .claude/skills/supabase-known-pitfalls

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Use when reviewing Supabase code, onboarding developers, auditing an existing project, or debugging unexpected behavior — catches the twelve most common Supabase mistakes: exposing the service_role key in client bundles, forgetting to enable RLS, skipping connection pooling in serverless, .single() throwing on empty results, missing .select() after insert/update, ignoring { data, error }, creating multiple client instances, and not using generated types. Trigger with phrases like "supabase mistakes", "supabase anti-patterns", "supabase pitfalls", "supabase code review", "supabase gotchas", "supabase debugging", "what not to do supabase", "supabase common errors".
671 chars✓ has a “when” triggerlonger than Claude Code's old 250-char listing cap (fine on current versions)
Intermediate

Key capabilities

  • Identify service_role key exposure in client bundles
  • Detect tables without Row Level Security enabled
  • Find overly permissive RLS policies
  • Verify connection pooling usage in serverless environments
  • Ensure proper handling of { data, error } responses
  • Check for missing .select() after mutations

How it works

This skill reviews a Supabase codebase against a list of common anti-patterns, categorized by severity. It provides detection methods and correct code patterns for each pitfall.

Inputs & outputs

You give it
Supabase project codebase and configuration
You get back
Identified anti-patterns, security flaws, performance bottlenecks, and recommended fixes

When to use supabase-known-pitfalls

  • Auditing Supabase projects
  • Debugging common Supabase errors
  • Improving code quality

About this skill

Supabase Known Pitfalls

Overview

The twelve most common Supabase mistakes, ranked by severity: security (service_role exposure, missing RLS, permissive policies, no connection pooling), data integrity (ignoring { data, error }, missing .select() after mutations, .single() on optional results), and performance / maintainability (select('*'), N+1 queries, missing FK indexes, multiple client instances, no generated types). Each pitfall shows the broken code, why it fails, and the correct pattern using createClient from @supabase/supabase-js.

This SKILL.md carries the full pitfall table plus one representative fix per category. The verbatim broken-vs-correct code and detection queries for all twelve live in references/pitfalls.md — drill in there for depth.

Prerequisites

  • Access to a Supabase project codebase for review
  • @supabase/supabase-js v2+ installed
  • Basic understanding of Row Level Security (RLS)

Instructions

Work the pitfalls top-down by severity. Fix every Critical finding before moving on — a single security miss can expose the whole database.

#PitfallSeverityFix
1service_role key in client bundleCriticalanon key on client; service_role server-only, no NEXT_PUBLIC_
2Table without RLSCriticalALTER TABLE … ENABLE ROW LEVEL SECURITY right after CREATE TABLE
3Overly permissive RLS policyCriticalscope USING (…) to auth.uid(), never USING (true) for writes
4No connection pooling in serverlessCriticalpooled string (Supavisor, port 6543), not the direct 5432 URL
5Ignoring { data, error }Highdestructure both; check error before touching data
6Missing .select() after mutationHighchain .select('cols') — mutations return null otherwise
7.single() on optional resultHighuse .maybeSingle() for 0-or-1; .single() only for guaranteed 1
8select('*') everywhereMediumname the columns — smaller payload, typed, no leakage
9N+1 query loopMediumPostgREST embedded join, or batch with .in()
10FK column without indexMediumCREATE INDEX on every foreign-key column
11Multiple client instancesLowsingleton in lib/supabase.ts, imported everywhere
12Hand-written DB typesLowsupabase gen types typescript --linked

Step 1 — Security (Critical, pitfalls 1-4)

The service_role key bypasses all RLS, so it must never reach a browser bundle. Split the client by trust boundary:

// Client (browser): anon key — respects RLS
const supabase = createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!)

// Server only (API routes, server actions): service_role, NO NEXT_PUBLIC_ prefix
const supabaseAdmin = createClient(url, process.env.SUPABASE_SERVICE_ROLE_KEY!,
  { auth: { autoRefreshToken: false, persistSession: false } })

Then confirm RLS is enabled on every table, tighten any USING (true) policy to auth.uid(), and use the pooled connection string in serverless. Full broken-vs-correct code and the SQL detection queries for pitfalls 1-4 are in the Security section of references/pitfalls.md.

Step 2 — Data Integrity (High, pitfalls 5-7)

Supabase returns { data, error } and mutations return null unless you ask for the row back:

const { data, error } = await supabase
  .from('orders').insert(order)
  .select('id, status')   // without .select(), data is null
  .maybeSingle()          // .single() throws PGRST116 on 0 rows
if (error) throw new Error(`Order failed: ${error.message}`)

See the Data Integrity section of references/pitfalls.md for the .single() vs .maybeSingle() rule of thumb and each failure mode.

Step 3 — Performance & Maintainability (Medium/Low, pitfalls 8-12)

Name your columns, collapse N+1 loops into a single embedded join, index foreign keys, share one client instance, and use generated types:

// One query instead of 1 + N — PostgREST embeds the FK relation
const { data } = await supabase
  .from('projects')
  .select('id, name, tasks (id, title, status)')

The full singleton pattern, the FK-index detection query, and the supabase gen types workflow are in the Performance and Maintainability section of references/pitfalls.md.

Output

  • Security pitfalls identified: service_role exposure, missing RLS, permissive policies, no connection pooling
  • Data integrity pitfalls fixed: { data, error } handling, .select() after mutations, .maybeSingle() usage
  • Performance pitfalls resolved: column-specific selects, JOIN queries, FK indexes
  • Maintainability improved: singleton client, generated types
  • Detection commands for automated scanning of each pitfall

Error Handling

IssueCauseSolution
PGRST116: JSON object requested, multiple (or no) rows returnedUsed .single() when 0 or 2+ rows matchUse .maybeSingle() for optional lookups
data is null after insertMissing .select() chainAdd .select('column1, column2') after .insert()
TypeError: Cannot read property of nullDestructured only data, ignoring errorAlways destructure { data, error } and check error first
too many connections for roleDirect connection from serverlessUse pooled connection string (port 6543)
permission denied for tableRLS blocking access, no matching policyCheck RLS policies match the authenticated user's JWT claims
relation does not existTable name typo, not caught at compile timeUse generated types for compile-time validation

More operator-facing failure modes (legacy codebases, false positives, fixes that break tests): references/errors.md.

Examples

Quick Security Audit

# Check for the three critical code-level security pitfalls in one pass
echo "=== Pitfall 1: Service role in client code ==="
grep -rn 'SERVICE_ROLE' --include="*.tsx" --include="*.ts" src/ app/ components/ 2>/dev/null || echo "Clean"

echo "=== Pitfall 2: Tables without RLS (run in SQL Editor) ==="
echo "SELECT tablename FROM pg_tables WHERE schemaname='public' AND rowsecurity=false;"

echo "=== Pitfall 3: Overly permissive policies (run in SQL Editor) ==="
echo "SELECT tablename, policyname FROM pg_policies WHERE qual='true' AND cmd!='r';"

Code Review Checklist

### Security
- [ ] No SERVICE_ROLE_KEY in client-side code or NEXT_PUBLIC_* vars
- [ ] RLS enabled on all new tables; policies scope to auth.uid() (no USING(true) writes)
### Data Integrity
- [ ] All calls destructure { data, error } and check error
- [ ] .select() chained after insert/update/upsert; .maybeSingle() for optional lookups
### Performance & Maintainability
- [ ] Columns named in .select() (no select('*')); no N+1; FK columns indexed
- [ ] Single createClient instance; generated types; pooled connection string in serverless

More detection one-liners: references/examples.md. Every pitfall's full before/after code: references/pitfalls.md.

Resources

Next Steps

This completes the Supabase pitfalls reference. To start a new project with best practices from day one, see supabase-hello-world.

Prerequisites

Access to a Supabase project codebase for review@supabase/supabase-js v2+ installedBasic understanding of Row Level Security (RLS)

Limitations

  • Requires manual review of code and SQL queries for full verification
  • Detection queries may not cover all possible variations of anti-patterns
  • Fixes may require changes to existing application logic

How it compares

This workflow systematically identifies and corrects common Supabase mistakes, providing specific fixes unlike a general code review.

Compared to similar skills

supabase-known-pitfalls side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
supabase-known-pitfalls (this skill)127dReviewIntermediate
pida-code-review04moNo flagsIntermediate
supabase-migration-deep-dive127dReviewIntermediate
supabase-postgres-best-practices46moNo flagsIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

pida-code-review

Team-PIDA

Use when reviewing a PIDA branch, diff, or PR. Focus on bugs, regressions, missing tests, API contract drift, persistence risks, and operational issues before style comments.

00

supabase-migration-deep-dive

jeremylongshore

Execute Supabase major re-architecture and migration strategies with strangler fig pattern. Use when migrating to or from Supabase, performing major version upgrades, or re-platforming existing integrations to Supabase. Trigger with phrases like "migrate supabase", "supabase migration", "switch to supabase", "supabase replatform", "supabase upgrade major".

10

supabase-postgres-best-practices

davila7

Postgres performance optimization and best practices from Supabase. Use this skill when writing, reviewing, or optimizing Postgres queries, schema designs, or database configurations.

439

supabase-common-errors

jeremylongshore

Execute diagnose and fix Supabase common errors and exceptions. Use when encountering Supabase errors, debugging failed requests, or troubleshooting integration issues. Trigger with phrases like "supabase error", "fix supabase", "supabase not working", "debug supabase".

430

supabase-policy-guardrails

jeremylongshore

Implement Supabase lint rules, policy enforcement, and automated guardrails. Use when setting up code quality rules for Supabase integrations, implementing pre-commit hooks, or configuring CI policy checks for Supabase best practices. Trigger with phrases like "supabase policy", "supabase lint", "supabase guardrails", "supabase best practices check", "supabase eslint".

331

convex-best-practices

waynesutton

Guidelines for building production-ready Convex apps covering function organization, query patterns, validation, TypeScript usage, error handling, and the Zen of Convex design philosophy

312

Search skills

Search the agent skills registry