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.
