supabase-fullstack
Skill1 starsChanged 40 days agoApache-2.0View on GitHub
Complete Supabase workflow — frontend (supabase-js, SSR, Next.js, React, auth/sessions), backend (Python, CLI, PostgreSQL, RLS), and DevOps (migrations, edge functions, MCP). Merged from official @supabase/skills (frontend) + hermes-skills supabase-integration (backend). Use for any Supabase task regardless of stack.
- Reads credentials
In this repository18 other files it gives its agents.
- agent-repo-handoff-loopSkill
- device-screen-verificationSkill
- flutter-android-build-systemSkill
- flutter-design-anti-patternsSkill
- flutter-ios-build-systemSkill
- flutter-isar-clean-arch-setupSkill
- flutter-isar-testingSkill
- flutter-lessons-patternsSkill
- flutter-patternsSkill
- flutter-sdk-changelogSkill
- flutter-soul-stewardshipSkill
- github-project-auditSkill
- mcp-bridge-patternsSkill
- repo-front-doorSkill
- skill-ecosystem-syncSkill
- specification-writingSkill
- translation-fidelitySkill
- what-if-analysisSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 5 are distinctive, and 12 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
2. Verify your work: After any fix, run a test query.
- Distinctive: line 27
3. Recover from errors, don't loop: If an approach fails after 2-3 attempts, stop and reconsider.
- Very specific: line 41
Never expose
service_rolekey in public clients: Use publishable keys for frontend. - Very specific: line 47
TO authenticatedalone is BOLA/IDOR: Always combine with ownership predicate: - Very specific: line 60
SECURITY DEFINERfunctions bypass RLS: Never add SECURITY DEFINER to resolve a permission error. - Very specific: line 91
Check .mcp.json has correct server URL
- Very specific: line 100
Use execute_sql (MCP) or supabase db query (CLI) to iterate.
- Very specific: line 103
Run supabase db advisors → fix issues
- Very specific: line 127
Install: Use the project venv Python explicitly.
- Distinctive: line 197
Always create THREE files:
- Very specific: line 214
Read schema file (e.g., app-spec/INIT-03_supabase_schema.md)
- Very specific: line 217
Verify each table: client.table("<name>").select("*").limit(1).execute()
- Very specific: line 218
Verify RLS — query pg_policies directly
- Very specific: line 219
Verify all tables have rowsecurity = true in pg_tables
- Very specific: line 220
Run flutter analyze after any credential refactoring
- Distinctive: line 253
Fix: ALWAYS use the project venv Python explicitly.
- Distinctive: line 265
Use a slightly different name.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Supabase Fullstack
Complete Supabase knowledge covering frontend, backend, CLI operations, and security. Merged from the official Supabase agent skill (frontend focus) and production backend patterns from Azdal, CarSah, and Hermex Android.
When to Use
ANY task involving Supabase — Database, Auth, Edge Functions, Realtime, Storage, Vectors, Cron, Queues, client libraries (supabase-js, @supabase/ssr, supabase-py), Flutter integration, CLI operations, MCP server, schema changes, migrations, RLS, security audits.
Part 1: Frontend (Official Supabase)
Core Principles
1. Supabase changes frequently — verify against changelog before implementing.
Fetch https://supabase.com/changelog.md, scan for breaking-change tags, follow linked pages. Then look up the relevant topic using MCP search_docs or append .md to any docs URL.
2. Verify your work. After any fix, run a test query. A fix without verification is incomplete.
3. Recover from errors, don't loop. If an approach fails after 2-3 attempts, stop and reconsider. Try a different method, check documentation, inspect errors, review logs.
4. Exposing tables to the Data API: Newly created tables may not be auto-exposed via the Data (REST) API depending on Data API settings. anon and authenticated roles may need explicit GRANT access. This is separate from RLS.
5. RLS on every table in exposed schemas (includes public by default). After enabling RLS, create policies matching the actual access model — don't default every table to the same auth.uid() pattern.
Security Checklist
Auth & Session Security
- Never use
user_metadatain JWT authorization.raw_user_meta_datais user-editable. Store authorization data inraw_app_meta_data/app_metadata. - Deleting a user does not invalidate existing tokens. Sign out/revoke sessions first. Validate
session_idagainstauth.sessionsfor strict guarantees. - JWT claims are not always fresh — tokens must be refreshed to pick up new
app_metadata.
API Key & Client Exposure
- Never expose
service_rolekey in public clients. Use publishable keys for frontend.NEXT_PUBLIC_env vars are sent to browser.
RLS, Views & Privileged Code
- Views bypass RLS by default. Postgres 15+:
CREATE VIEW ... WITH (security_invoker = true). Older: revoke access fromanon/authenticatedor put in unexposed schema. - UPDATE requires SELECT policy. Without SELECT, updates silently return 0 rows.
auth.role()is deprecated — useTO authenticatedorTO anoninstead.auth.role() = 'authenticated'breaks silently with anonymous sign-ins.TO authenticatedalone is BOLA/IDOR. Always combine with ownership predicate:CREATE POLICY "example" ON table_name FOR SELECT TO authenticated USING ( (SELECT auth.uid()) = user_id );- UPDATE needs both USING and WITH CHECK. Without
WITH CHECK, users can reassignuser_id:CREATE POLICY "example" ON table_name FOR UPDATE TO authenticated USING ( (SELECT auth.uid()) = user_id ) WITH CHECK ( (SELECT auth.uid()) = user_id ); SECURITY DEFINERfunctions bypass RLS. Never addSECURITY DEFINERto resolve a permission error. PreferSECURITY INVOKER.SECURITY DEFINERinpublicis callable by all roles. Postgres grantsEXECUTEtoPUBLICby default. Keep in non-exposed schema, includeauth.uid()check, runsupabase db advisors.
Storage Access Control
- Storage upsert requires INSERT + SELECT + UPDATE. Granting only INSERT silently fails on replacement.
Dependency Security
- Always pin versions and commit lockfiles for supabase-js, @supabase/ssr, supabase-py, etc.
For full security guide: https://supabase.com/docs/guides/security/product-security.md
Supabase CLI
supabase --help # All top-level commands
supabase <group> --help # Subcommands
supabase <group> <command> --help # Flags for specific commandKnown gotchas:
supabase db queryrequires CLI v2.79.0+supabase db advisorsrequires CLI v2.81.3+- For imperative migrations:
supabase migration new <name>first — never invent filenames - For declarative schemas: edit
supabase/schemas/, then generate migration
Supabase MCP Server
Setup: https://supabase.com/docs/guides/getting-started/mcp
Troubleshooting:
curl -so /dev/null -w "%{http_code}" https://mcp.supabase.com/mcp— 401 = server up- Check
.mcp.jsonhas correct server URL - Authenticate via OAuth 2.1 flow
Schema Changes Workflow
Declarative (when supabase/schemas/ exists)
Edit schema files → generate migration → review. See Declarative schemas guide.
Imperative (no declarative schemas)
Use execute_sql (MCP) or supabase db query (CLI) to iterate. Do NOT use apply_migration for iteration — it writes migration history on every call.
When ready to commit:
- Run
supabase db advisors→ fix issues - Review Security Checklist
supabase db pull <name> --local --yes- Verify:
supabase migration list --local
Part 2: Backend & DevOps (Hermes Skills)
Connection Methods (3 tiers)
Tier 1: supabase-py (Python — fastest for agent use)
from supabase import create_client
url = "https://<project-ref>.supabase.co"
key = "<anon-key>"
client = create_client(url, key)
# Verify connection
result = client.table("your_table").select("*").limit(1).execute()Install: Use the project venv Python explicitly. Do NOT use system pip3/python3.
Tier 2: Supabase CLI (npx — migrations, local dev, edge functions)
npx supabase --version
npx supabase login # INTERACTIVE — needs browser/TTY
npx supabase init
npx supabase link --project-ref <ref>
npx supabase db pushTier 3: Direct PostgreSQL (psql — raw SQL access)
PGPASSWORD='<password>' psql "postgresql://postgres:***@db.<ref>.supabase.co:5432/postgres"Auth Configuration via config push
Edit supabase/config.toml → push without Dashboard:
npx supabase config push --project-ref <ref>
# For automated runs:
echo "Y" | npx supabase config push --project-ref <ref>Verification:
curl -s "https://<ref>.supabase.co/auth/v1/settings" \
-H "apikey: <anon-key>" \
-H "Authorization: Bearer <anon-key>" \
| python3 -c "import json,sys; d=json.load(sys.stdin); print('anonymous_users:', d['external']['anonymous_users'])"| Task | Method |
| Enable anonymous sign-ins | config push ✅ |
| Toggle email confirmations | config push ✅ |
| Add OAuth provider (Google, Apple) | Dashboard (secrets required) |
| Change JWT expiry | config push ✅ |
| Configure MFA | config push ✅ |
Flutter Integration
PITFALL: Hardcoded Supabase credentials in main.dart
Anti-pattern:
await Supabase.initialize(
url: 'https://kqhyjngtquutzdvjfbnf.supabase.co', // ❌ hardcoded
publishableKey: 'eyJhbG...6Bik', // ❌ hardcoded
);Fix — use Platform.environment:
import 'dart:io' show Platform;
await Supabase.initialize(
url: Platform.environment['SUPABASE_URL'] ?? '',
publishableKey: Platform.environment['SUPABASE_ANON_KEY'] ?? '',
);For mobile: --dart-define-from-file=.env at build time.
.env Template
Always create THREE files:
.env— real credentials (gitignored).env.example— placeholder values, safe to commit.env.template— instructional header for new developers
.gitignore MUST use negation:
.env
.env.*
!.env.example
!.env.templateWithout ! negations, .env.* blocks ALL env variants including templates.
Schema Deployment Workflow
- Read schema file (e.g.,
app-spec/INIT-03_supabase_schema.md) - Open SQL Editor:
https://app.supabase.com/project/<ref>/sql/new - Execute SQL blocks in order
- Verify each table:
client.table("<name>").select("*").limit(1).execute() - Verify RLS — query
pg_policiesdirectly - Verify all tables have
rowsecurity = trueinpg_tables - Run
flutter analyzeafter any credential refactoring
Region Selection (Middle East / Saudi Arabia)
| Region | Location | Latency | Notes |
eu-central-1 | Frankfurt 🇩🇪 | ~80ms | Recommended for ME |
ap-south-1 | Mumbai 🇮🇳 | ~90ms | Closer, less reliable |
eu-west-1 | Ireland 🇮🇪 | ~120ms | Acceptable fallback |
npx supabase projects create "<name>" \
--org-id <org-id> \
--db-password '<password>' \
--region eu-central-1 \
--size nanoRegion CANNOT be changed later — to migrate, create new project and transfer.
Part 3: Production Pitfalls (ALL)
PITFALL 1: supabase login fails in non-TTY
Cannot use automatic login flow inside non-TTY environments.Fix A: User runs npx supabase login in their terminal.
Fix B: Generate access token at supabase.com/dashboard/account/tokens → npx supabase login --token <token> or export SUPABASE_ACCESS_TOKEN=<token>.
PITFALL 2: Python venv version mismatch
System Python 3.13 importing hermes venv's Python 3.11 pydantic → ModuleNotFoundError.
Fix: ALWAYS use the project venv Python explicitly.
PITFALL 3: First query fails with PGRST205
NORMAL on fresh project — auth succeeded but no tables exist. Connection is working.
PITFALL 4: projects delete rejects --project-ref flag
Fix: The ref is POSITIONAL: npx supabase projects delete <ref> --yes — NOT --project-ref <ref>.
PITFALL 5: API keys ALWAYS truncated in CLI
supabase projects api-keys truncates in ALL formats (text AND JSON). Use Dashboard or .env for full keys.
PITFALL 6: Project name collision
Use a slightly different name. Old project must be deleted first to reuse exact name.
PITFALL 7: .env.template blocked by .env.* gitignore
Add negation: !.env.template.
PITFALL 8: Tests + Agent Approval ≠ Verification (LL-010)
From Azdal Stage 4: 5 critical bugs found on live device AFTER 34/34 tests passing + Zero-Trust Auditor APPROVE + SCSI Guardian ALL CLEAR. Always verify on real device with direct database queries.
PITFALL 9: Regex Pre-Filter Gates (LL-011)
Local RegExp gates before LLM classifiers are fine for cost optimization — but MUST have a fallback path. A miss degrades to confidently-wrong-and-silent, not "slower but correct."
PITFALL 10: Disabled Button Colors (LL-011)
ElevatedButton.styleFrom(backgroundColor:, foregroundColor:) only styles the ENABLED state. Once onPressed: null, Material silently substitutes its default disabled palette. Always set disabledBackgroundColor/disabledForegroundColor explicitly.
Verification Checklist
- supabase-py imports without error (use project venv python)
create_client(url, key)succeeds- At least one table query returns 200
npx supabase --versionreturns version.envfile created,.env.example+.env.templatecommitted- Schema deployed and verified via direct DB query
- RLS policies verified via
pg_policies - All tables have
rowsecurity = true - No hardcoded credentials in source code
- Security Checklist reviewed for auth/storage/views changes
- Live device verification — tests passing ≠ it works (LL-010)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

