Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Postgres performance optimization and best practices guide maintained by Supabase
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/security-rls-performance.md
1---2title: Optimize RLS Policies for Performance3impact: HIGH4impactDescription: 5-10x faster RLS queries with proper patterns5tags: rls, performance, security, optimization6---78## Optimize RLS Policies for Performance910Poorly written RLS policies can cause severe performance issues. Use subqueries and indexes strategically.1112**Incorrect (function called for every row):**1314```sql15create policy orders_policy on orders16using (auth.uid() = user_id); -- auth.uid() called per row!1718-- With 1M rows, auth.uid() is called 1M times19```2021**Correct (wrap functions in SELECT):**2223```sql24create policy orders_policy on orders25using ((select auth.uid()) = user_id); -- Called once, cached2627-- 100x+ faster on large tables28```2930Use security definer functions for complex checks:3132`SECURITY DEFINER` functions run with the creator's privileges and bypass RLS on any tables they touch — which is what makes them useful for internal lookups, but also what makes them dangerous if misused. Always include an explicit `auth.uid()` check inside the function body, keep them in a non-exposed schema, and revoke `EXECUTE` from any role that shouldn't call them directly.3334```sql35-- Create helper function in a private schema36create or replace function private.is_team_member(team_id bigint)37returns boolean38language sql39security definer40set search_path = ''41as $$42select exists (43select 1 from public.team_members44-- always check the calling user's identity inside the function45where team_id = $1 and user_id = (select auth.uid())46);47$$;4849-- Revoke direct execution from public roles50revoke execute on function private.is_team_member(bigint) from PUBLIC, anon, authenticated, service_role;5152-- Use in policy (indexed lookup, not per-row check)53create policy team_orders_policy on orders54using ((select private.is_team_member(team_id)));55```5657Always add indexes on columns used in RLS policies:5859```sql60create index orders_user_id_idx on orders (user_id);61```6263Reference: [RLS Performance](https://supabase.com/docs/guides/database/postgres/row-level-security#rls-performance-recommendations)64