RLS glossary: every term, in plain language
Row Level Security vocabulary shrinks to a dozen terms once each is anchored to the thing it names: a flag on a table, rules attached to that flag, roles those rules address, and words for how the arrangement changes over time. Every entry below opens with a definition complete enough to quote.
The glossary is maintained by hand and updated as usage shifts; where a term names RowShield product behaviour rather than Postgres mechanics, the entry says so. Postgres, PostgREST and Supabase are described descriptively throughout, and RowShield is an independent product, not affiliated with or endorsed by Supabase.
RowShield does not detect this yet. This guide gives you the catalog queries to check it yourself. The nine rules that do ship are listed on the rules index.
The mechanism
Row Level Security (RLS) — a Postgres property of a table, switched on per table with ENABLE ROW LEVEL SECURITY. When on, Postgres consults the table's policies for every query from every role except owners and holders of BYPASSRLS. It is Postgres machinery that Supabase exposes; the database enforces it regardless of what your application believes.
Policy — a named rule attached to one table, declaring which command it governs (SELECT, INSERT, UPDATE, DELETE or ALL), which roles it applies to, and the conditions rows must satisfy. Policies grant; absence of a matching policy denies. Under enabled RLS, no policies means everything denied to client roles.
USING — the condition filtering which existing rows a caller can see or target. Evaluated per candidate row, spliced into the query like a WHERE clause you had typed by hand. A USING that is constant true filters nothing.
WITH CHECK — the condition validating rows a caller tries to write. USING governs visibility; WITH CHECK governs admission of new or modified versions. Absent on INSERT and UPDATE, nothing constrains attribution — the write-hole MISSING_WITH_CHECK reports.
Annotated, the anatomy looks like this:
CREATE POLICY "owners_read_own_projects" -- the policy: a named rule on one table ON public.projects FOR SELECT -- the command it governs TO authenticated -- the roles it applies to USING (user_id = (SELECT auth.uid())); -- USING: rows you may see -- A write command would add: -- WITH CHECK (user_id = (SELECT auth.uid())); -- validating rows you may create or alter.
Failure vocabulary
Tautology — a policy whose condition is always true, typically USING (true): machinery present, dashboard green, nothing filtered. The permissive form is the dangerous one; a RESTRICTIVE tautology narrows nothing but grants nothing either, which is why RowShield ignores it deliberately.
Roles, keys and bypasses
FORCE (FORCE ROW LEVEL SECURITY) — the companion flag making policies apply to the table owner too. Without it, migrations and psql sessions running as owner bypass every policy you wrote. One statement, routinely forgotten.
BYPASSRLS — a role attribute, carried by Supabase's service_role among others, exempting its holder from all RLS. Any credential bearing it is a master key; policies are decoration to whoever holds it.
service_role — the Supabase key identifying a server trusted to bypass RLS. Safe only where browsers cannot fetch it; in a client bundle it is a published master key, which is why SERVICE_ROLE_KEY_EXPOSED rates critical and rotate-first.
anon — the Supabase key identifying an unauthenticated caller. Public by design and meant to be: it is the identity of least privilege, bounded entirely by your policies. Treating it as a secret leads nowhere; bounding it leads everywhere.
The public surface
PostgREST — the component serving your database over HTTP, generating the /rest/v1 endpoints your clients call. It exposes the tables it finds in the public schema to whoever presents a valid key, which is why "reachable through PostgREST" is shorthand for "on the internet".
Change over time
Schema drift — distance growing between the posture you believe the project holds and the one it reached while you were elsewhere: the new table without policies, the rewritten policy, the flipped bucket. Drift is not a mistake anyone made; it is the default behaviour of projects that change.
Transition — the event vocabulary for drift: a finding created, resolved, or regressed (a fixed state come back). A precision note, because this site is read by people who check claims: transitions are product behaviour layered on the scan, not a named detection rule — the nine shipped rules detect states, and comparing scans dates them. Transition alerting is also why silence means unchanged.
Remediation SQL — the generated statements that repair a finding, built from your actual columns rather than placeholders: owner-scoped policies, FORCE included, ALTER POLICY for expression fixes. Generated by RowShield, applied by you — automation proposes, a human applies.
Scope note to close, stated the way this site states everything: RowShield does not automate glossary maintenance or any definition on this page — it is a hand-written reference. What the product automates is the checking those definitions describe: catalog rules over RLS state and policy sanity, and a probe that tests what the anon key can read on the live surface.
Frequently asked
- Is RLS a Supabase feature or a Postgres feature?
- Postgres. Supabase exposes it through the dashboard and wires roles around it, but the enforcement lives in the database engine, which is why catalog queries see the truth regardless of tooling.
- What is the shortest correct summary of USING versus WITH CHECK?
- USING decides which existing rows you can see or target; WITH CHECK decides which new or altered row versions you may write. Reads need the first, writes need both.
- Where can I run the queries in this glossary?
- Anywhere an authenticated connection exists — the SQL editor, psql, or a CI job — since they read catalog metadata only and return identical results from every seat.
Check your project in about ten seconds
Paste a URL. No signup, no writes, nothing stored.
Run the free audit