What does security_definer_view mean, and how do I fix it?
security_definer_view is the Supabase Security Advisor error for a view the Data API exposes that runs with its owner's permissions instead of the caller's, so it skips the row level security policies of the tables under it. Postgres views behave that way by default. The fix, on Postgres 15 and later, is alter view ... set (security_invoker = true), so the view applies each caller's policies.

It is one of several Security Advisor warnings. For the others, see what each Supabase Security Advisor warning means.
How to fix security_definer_view, then check the fix
- Make the view run as the caller. It keeps its name, columns and grants:
alter view public.todo_titles set (security_invoker = true); - Put the option in the migration that defines the view too, the way Supabase's lint docs write it. A later create or replace view without it turns it off again: on the test container, reloptions went from {security_invoker=on} to empty and the lint fired again.
create or replace view public.todo_titles with (security_invoker = on) as select id, title from public.todos; - Check the tables under the view. Each caller now sees only the rows their own policies allow, so a table with RLS on and no policy for that role returns nothing through the view either.
- Confirm the option is set. reloptions should show security_invoker=true or security_invoker=on:
select relname, reloptions from pg_class where oid = 'public.todo_titles'::regclass; - Run the Security Advisor again. The view should be gone from the list:
supabase db advisors --linked --type security
When security_definer_view is intended
The lint's source flags a view only on Postgres 15 and later, in a schema the Data API exposes, when anon or authenticated can select from it and security_invoker is not set.
A view meant to show more than the tables allow
A public leaderboard that counts rows in a private table needs its owner's rights to see those rows. Keep it, select only what every visitor may see, and write down why: Supabase says some findings may be intentional. The Advisor keeps listing it.
A view only your server reads
Revoke it from the browser roles, or move it to a schema the API does not expose. Either takes it out of the lint, and the secret or service role key can still read it.
revoke all on public.todo_titles from anon, authenticated;
Related guides
Sources
Why are Postgres views security definer by default?
Supabase's lint docs call it "an unintuitive default, chosen for backwards compatibility with older Postgres versions". Postgres added security_invoker in version 15. A view without it checks permissions as its owner, usually postgres, which owns the tables and so is not held to their RLS.
Is a view in a private schema flagged?
No. The lint checks only the schemas the Data API exposes, public by default, so a view in a schema that is not listed under Exposed schemas is not reported.