LEARN IT. BUILD WITH IT.
The Supabase Field Manual
Practical Supabase development, from schema and auth to reliable operations

About this workbook
A practical guide to building with Supabase and PostgreSQL: schemas, auth and row-level security, client integration, APIs, storage, realtime, functions and operations. Combines introductions, references, guides, patterns and field notes.
THE COMPLETE READING PATH
Explore the chapters.
Read in order or go straight to the problem you are working on. Every chapter is available online.
Part 1: Migration
- Verify a self-hosted to hosted Supabase cutover table by table 3 min
- Storage buckets and objects don't come with your Postgres dump 2 min
Part 2: RLS & Auth
- Hosted Supabase signs user JWTs with ES256, not RS256 or HS256 2 min
- Auth hooks are instance config, not rows — bind them per project 3 min
- Test RLS with set local role and request.jwt.claims in a transaction 3 min
- Magic links: allow-listed redirect, same OTP type on verify, no ghosts 3 min
- Custom claims: the access-token hook stamps roles into the JWT 3 min
- Disable public signups; mint users server-side with app_metadata 3 min
- OAuth callback: exchange the code, check the tenant, set up once 3 min
- Anonymous sign-ins mint real authenticated JWTs; gate on is_anonymous 2 min
- Verify Supabase user JWTs at the edge with jose and the project JWKS 3 min
- Multi-tenancy: tenant id on every row, tenant list in the JWT 3 min
- A policy that reads another table runs that table's policies too 3 min
- Wrap auth calls in (select …) and index the policy column 3 min
- UPDATE policies have two halves; a blocked write succeeds silently 3 min
- Resolve the tenant from the host, then rely on the claim, not the URL 3 min
Part 3: Migrations & Pooling
- Record each migration's checksum in the same transaction as its DDL 3 min
- Use the session pooler on 5432 for DDL; the direct host is IPv6-only 2 min
Part 4: Self-hosting
Part 5: Backups & Performance
- Daily backups roll back a day, PITR a minute; neither restores Storage 3 min
- Find slow queries: pg_stat_statements, explain analyze, inspect db 3 min
Part 6: Client & SSR
- Publishable and secret keys replace anon and service_role 2 min
- SSR: one server client per request, and let it write the cookies 3 min
- Server-side: trust getClaims() or getUser(), never getSession() 2 min
Part 7: Data API
- PostgREST caps responses at max_rows; page with range() and a count 3 min
- Expose only what PostgREST should serve: a narrow schema, no defaults 3 min
- RLS hides rows; column privileges hide columns and break select('*') 2 min
- A pre-request function is PostgREST middleware: keys, tenants, 403s 3 min
Part 8: Edge Functions & Webhooks
- Database Webhooks are pg_net triggers; make every receiver idempotent 3 min
- Run an Edge Function per new row: webhook in, secret checked 4 min
Part 9: Extensions & Cron
- pg_cron schedules SQL inside Postgres; cross-service jobs stay outside 3 min
- pgvector search: a vector column, one model, an RPC with <=>, HNSW 3 min
- pgTAP tests schema and policies in SQL, rolled back afterwards 3 min
- Wrappers turn Stripe or S3 into foreign tables; keep them private 2 min
Part 10: Getting Started
- Supabase is Postgres behind Kong: Auth, PostgREST, Realtime, Storage 3 min
- supabase start runs the stack locally; diff, push and gen types there 3 min
- Your first table: enable RLS, write one policy, query it 3 min
Part 11: Realtime
Part 12: Release tooling
Part 13: Schema & Postgres
- Set created_by in a BEFORE INSERT trigger, never from the client 3 min
- A SECURITY DEFINER RPC is a controlled hole in RLS: guard it, pin it 3 min
Part 14: Security
- Vault keeps secrets encrypted in Postgres; read them in definer code 2 min
- Pin search_path in definer functions; keep extensions out of public 2 min
- Security Advisor lints to clear before launch, performance ones after 3 min
- Network restrictions and SSL cover Postgres, not the HTTPS APIs 2 min
Part 15: Storage
Want help applying the ideas?
Bring the workflow you want to build or improve.