The PostgreSQL documentation describes row security policies as rules that "restrict, on a per-user basis, which rows can be returned by normal queries or inserted, updated, or deleted by data modification commands." By default a table has no policies, so any role with table privileges sees every row (PostgreSQL docs).
Supabase's guide gives the clearest mental model: "Think of a policy as adding a WHERE clause to every query" (Supabase). QueryPlane's walkthrough adds that this rewrite happens before planning, so the policy predicate takes part in plan selection and can use indexes like a hand-written filter. RLS is not a post-filter applied after rows are fetched (QueryPlane).
Why move the filter into the database? AWS's post on multi-tenant isolation describes three ways to separate tenants: a database per tenant (silo), a schema per tenant (bridge), or shared tables with a tenant key (pool). The pool model is cheapest to run, but without RLS it is "commonly implemented by hoping the correct WHERE clause is implemented in every SQL statement" (AWS). RLS keeps the cost advantage and removes the hope.
There is a second benefit. Supabase notes that because RLS is a database primitive, it also protects data reached through third-party tools, scripts and reporting connections, which makes it defense in depth rather than one more application check (Supabase).



