Supabase RLS launch checklist for indie MVPs
Enable Row Level Security, revoke excess grants, keep service_role server-side, then judge Free pause and backup limits before you rely on it in production.
The common MVP failure is not an ugly UI. It is an exposed table with a publishable key and no row level security. Anyone can read other people’s rows and sometimes write them. Supabase puts Postgres RLS on the critical path. This article does not choose between Supabase and Firebase. It covers a ship checklist from the official RLS guide, and when Free pause and backup limits force a plan change. Sources observed on 2026-09-26.
Respect the dangerous defaults
The RLS guide is blunt. A table in an exposed schema without RLS is readable and writable by any role with a grant. Adding policies does not revoke grants that already exist. On projects that still grant anon and authenticated by default, revoke what the app does not need. The service_role has full access and bypasses RLS, so it must stay server-side.
Indie apps often call Supabase from the browser with a publishable key. That path depends on RLS and correct grants. Putting service_role in frontend code, mobile binaries, or plaintext repos is locking the door and nailing the key to it.
Table wizards sometimes remind you to enable RLS. Hand-written SQL and older projects miss it more often. Make enable RLS a fixed trailing statement in migrations instead of relying on memory.
Five acceptance steps before launch
First, enable RLS on every table reached through the API. Second, grant anon and authenticated only the select, insert, update, and delete operations the app truly exposes; revoke the rest. Third, write a policy per operation, commonly using auth.uid() so users touch only their rows. Fourth, add allow and deny tests for anon and authenticated across CRUD. Fifth, run database tests until failures are gone.
Keep policy sentences short. Users read their own profile and insert rows they own. Paths that reassign owner to someone else stay closed. Admin work runs on the server with service_role in a controlled environment and an audit trail. Never ship a policy that is always true for convenience.
Treat storage buckets separately from tables. If object paths include user ids, add matching policies so URL guessing cannot download someone else’s file. Realtime subscriptions hit the same permission model; test with a second account that must not see your rows.
How far Free can carry you
Pricing lists Free at $0 per month with unlimited API requests, 50,000 monthly active users, 500MB database size, 5GB egress, and 1GB file storage, plus a note that Free projects pause after about a week of inactivity and that active projects are capped at two. Pro starts from about $25 per month for production scale. Free is for validation. It is not a promise of backups and uninterrupted uptime.
RLS exists on Free and Pro. Paying does not invent security. Shipping secure on Free means you accept pause and recovery risk. Paying for Pro without RLS means you subscribe to the accident.
A common Free split is one development project and one production project. Enable RLS in development too, or bad habits copy straight into production.
When RLS is not enough, and when not to launch
RLS does not replace server checks, abuse controls, or quotas. Payments, admin impersonation, and cross-tenant reports need a server boundary. If compliance demands residency or a contractual SLA, Free’s community support and pause rule may fail before you write more features. If nobody on the team can read SQL policies, add minimal tests before stacking product scope.
Seed at least two users when you test. One user’s success does not prove another user’s denial. Put deny cases in CI instead of relying on a manual click before release.
Scenario defaults
A personal tool with only your login still enables RLS and denies anonymous writes. Multi-tenant SaaS policies key off owner or org_id, with admin paths on the server. A content site may allow anon select on published rows while writes stay server-side. If you already have users and discover RLS was never enabled, freeze to read-only, add policies, and rotate keys before you keep operating exposed.
The narrow call. Default enable RLS, revoke excess grants, keep service_role server-side, and accept only with allow/deny tests. Free can validate; sustained commercial operation must face pause and backup gaps. Recheck live docs when policies change.
Add one release-check line. Open the table list, confirm exposed tables have RLS on, and sample a deny case. Without that line, feature checklists are optimistic. Practice key rotation at least yearly and document how publishable and server keys are replaced.
If you use Edge Functions, remember that returning data with service_role inside the function bypasses RLS for that path. Return minimal fields and keep full user rows out of logs. Security is layered. RLS is a required layer, not the only one.
Keep common policy templates in repo docs and adapt field names for new tables. Templates do not replace tests, but they lower the error rate of Friday-night policy edits.
Tools in this guide
