Postgres best practices
Views and functions that bypass RLS, and how to lock them down
A Postgres view runs with its owner's rights by default, so in Supabase a view on an RLS table can show every row to anyone. Create views `with (security_invoker = true)` so they obey the caller's RLS. Functions marked `security definer` also run as their owner: keep them in a private schema, set `search_path = ''` and grant execute only to the roles that need it.
Last updated
Why do views leak data?
Views are usually owned by `postgres`, which bypasses RLS. Unless the view uses `security_invoker`, a select on the view returns rows the caller could never read from the table. The Supabase Security Advisor flags these as security definer views.
create view public.my_notes
with (security_invoker = true) as
select id, title, created_at from public.notes;
-- Fix an existing view
alter view public.my_notes set (security_invoker = true);When is a security definer function safe?
- It lives in a schema the API does not expose, for example `private`.
- It sets `search_path = ''` and uses fully qualified names, so nobody can shadow a table or function.
- It checks the caller itself, with `auth.uid()`, before it returns data.
- `execute` is revoked from `public` and `anon` and granted only where needed.
create schema if not exists private;
create function private.my_team_ids()
returns setof uuid
language sql stable security definer
set search_path = ''
as $$
select team_id from public.memberships where user_id = (select auth.uid());
$$;
revoke execute on function private.my_team_ids() from public, anon;
grant execute on function private.my_team_ids() to authenticated;What about RPC functions in the public schema?
Every function in an exposed schema is callable through `/rest/v1/rpc/<name>` by anyone with the anon key, unless you revoke execute. Review each one: if it is `security definer`, it must check the caller. If it takes an ID as a parameter, it must check that the caller may use that ID.
Frequently asked questions
- Which Postgres version supports security_invoker views?
- Postgres 15 and later. Supabase projects run Postgres 15 or newer.
- How do I find risky views and functions?
- Open the Security Advisor in the Supabase dashboard. It lists security definer views, tables without RLS and functions with a mutable search_path.
- Does Supahound check this?
- Yes. The free posture scan lists views without security_invoker and newly exposed tables, alongside the Security Advisor findings.