Secure your Supabase application with these essential practices. From RLS policies to API key management.
Verify your app follows these best practices automatically.
Supabase provides powerful security features, but they need to be configured correctly. These practices help you leverage Supabase's security capabilities effectively.
Row Level Security is your primary defense. Without it, any authenticated user can read all data in a table.
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY; then create appropriate policies
-- No RLS enabled, all users can read all rows
SELECT * FROM profiles;-- RLS policy ensures users only see their own data
CREATE POLICY "Users can view own profile" ON profiles
FOR SELECT USING (auth.uid() = user_id);The service_role key bypasses all RLS. It should only be used in secure server environments, never in client code.
Use anon key for client-side, service_role only in server functions with restricted access
Wrap auth functions in select for better performance. This prevents re-evaluation for each row.
Use (select auth.uid()) = user_id instead of auth.uid() = user_id
USING (auth.uid() = user_id) -- Re-evaluates for each rowUSING ((select auth.uid()) = user_id) -- Evaluates once per queryEnsure your RLS policies handle type mismatches correctly to prevent bypasses.
Cast UUIDs explicitly and handle null cases in policies
Supabase Auth integrates with RLS through auth.uid(). Custom auth loses this integration.
Use Supabase Auth hooks and the auth schema, not custom user tables for authentication
Edge Functions run with service_role by default. Validate authentication in each function.
Always verify the JWT and check user permissions in Edge Functions
New tables have RLS disabled by default, exposing all data
Always enable RLS immediately when creating tables
Gives every user full database access, bypassing all security
Only use anon key in client code, service_role in secure server environments
Policies like 'true' for SELECT allow anyone to read everything
Always scope policies to the authenticated user's data
Following best practices is the first step. Verify your app is actually secure with a comprehensive security scan.
Scan Your App FreeYes, the anon key is designed to be public. It can only access data permitted by your RLS policies. The service_role key is the secret one that must never be exposed.
In Supabase dashboard, go to Table Editor - tables without RLS show a warning. Or run: SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';
Yes, Edge Functions run server-side and can safely use service_role. But always validate the user's JWT first and ensure they're authorized for the operation.
Last updated: January 2026