[{"data":1,"prerenderedAt":316},["ShallowReactive",2],{"blog-how-to/setup-supabase-rls":3},{"id":4,"title":5,"body":6,"category":297,"date":298,"dateModified":298,"description":299,"draft":300,"extension":301,"faq":302,"featured":300,"headerVariant":303,"image":302,"keywords":302,"meta":304,"navigation":305,"ogDescription":306,"ogTitle":302,"path":307,"readTime":302,"schemaOrg":308,"schemaType":309,"seo":310,"sitemap":311,"stem":312,"tags":313,"twitterCard":314,"__hash__":315},"blog/blog/how-to/setup-supabase-rls.md","How to Set Up Supabase Row Level Security (RLS)",{"type":7,"value":8,"toc":279},"minimark",[9,13,18,22,36,45,50,91,116,132,145,161,165,169,175,179,185,189,195,199,231,242,246,260],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,17],"h1",{"id":16},"how-to-set-up-supabase-row-level-security","How to Set Up Supabase Row Level Security",[19,20,21],"p",{},"The most important security setting for your Supabase project",[23,24,25,28],"tldr",{},[19,26,27],{},"TL;DR",[19,29,30,31,35],{},"Enable RLS on every table. Write policies for SELECT, INSERT, UPDATE, and DELETE. Use ",[32,33,34],"code",{},"auth.uid()"," to verify the user owns the data. Test with different users to make sure policies work. Never deploy with \"allow all\" rules.",[37,38,39,42],"warning-box",{},[19,40,41],{},"Why This Matters",[19,43,44],{},"Without RLS, anyone with your Supabase URL and anon key can read and modify ALL data in your database. This is the #1 security issue in Supabase apps.",[46,47,49],"h2",{"id":48},"step-by-step-guide","Step-by-Step Guide",[51,52,54,59,62,78,81],"step",{"number":53},"1",[55,56,58],"h3",{"id":57},"enable-rls-on-your-table","Enable RLS on your table",[19,60,61],{},"In the Supabase Dashboard:",[63,64,65,69,72,75],"ol",{},[66,67,68],"li",{},"Go to Table Editor",[66,70,71],{},"Select your table",[66,73,74],{},"Click on the \"RLS disabled\" button",[66,76,77],{},"Click \"Enable RLS\"",[19,79,80],{},"Or run this SQL:",[82,83,88],"pre",{"className":84,"code":86,"language":87},[85],"language-text","ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;\n","text",[32,89,86],{"__ignoreMap":90},"",[51,92,94,98,101,107,110],{"number":93},"2",[55,95,97],{"id":96},"create-a-select-policy","Create a SELECT policy",[19,99,100],{},"This controls who can read data:",[82,102,105],{"className":103,"code":104,"language":87},[85],"-- Users can only read their own data\nCREATE POLICY \"Users can view own data\"\nON your_table\nFOR SELECT\nUSING (auth.uid() = user_id);\n",[32,106,104],{"__ignoreMap":90},[19,108,109],{},"For public data that anyone can read:",[82,111,114],{"className":112,"code":113,"language":87},[85],"-- Anyone can read published posts\nCREATE POLICY \"Public can view published posts\"\nON posts\nFOR SELECT\nUSING (is_published = true);\n",[32,115,113],{"__ignoreMap":90},[51,117,119,123,126],{"number":118},"3",[55,120,122],{"id":121},"create-an-insert-policy","Create an INSERT policy",[19,124,125],{},"This controls who can create data:",[82,127,130],{"className":128,"code":129,"language":87},[85],"-- Users can only insert data for themselves\nCREATE POLICY \"Users can insert own data\"\nON your_table\nFOR INSERT\nWITH CHECK (auth.uid() = user_id);\n",[32,131,129],{"__ignoreMap":90},[51,133,135,139],{"number":134},"4",[55,136,138],{"id":137},"create-update-and-delete-policies","Create UPDATE and DELETE policies",[82,140,143],{"className":141,"code":142,"language":87},[85],"-- Users can only update their own data\nCREATE POLICY \"Users can update own data\"\nON your_table\nFOR UPDATE\nUSING (auth.uid() = user_id);\n\n-- Users can only delete their own data\nCREATE POLICY \"Users can delete own data\"\nON your_table\nFOR DELETE\nUSING (auth.uid() = user_id);\n",[32,144,142],{"__ignoreMap":90},[51,146,148,152,155],{"number":147},"5",[55,149,151],{"id":150},"test-your-policies","Test your policies",[19,153,154],{},"In the Supabase SQL Editor, test as different users:",[82,156,159],{"className":157,"code":158,"language":87},[85],"-- Test as a specific user\nSET request.jwt.claims.sub = 'user-id-here';\n\n-- Try to read data\nSELECT * FROM your_table;\n\n-- Try to read another user's data (should return empty)\nSELECT * FROM your_table WHERE user_id = 'other-user-id';\n\n-- Reset\nRESET request.jwt.claims.sub;\n",[32,160,158],{"__ignoreMap":90},[46,162,164],{"id":163},"common-policy-patterns","Common Policy Patterns",[55,166,168],{"id":167},"profiles-table","Profiles Table",[82,170,173],{"className":171,"code":172,"language":87},[85],"-- Anyone can view profiles\nCREATE POLICY \"Public profiles are viewable\"\nON profiles FOR SELECT USING (true);\n\n-- Users can update own profile\nCREATE POLICY \"Users can update own profile\"\nON profiles FOR UPDATE USING (auth.uid() = id);\n\n-- Users can insert their own profile on signup\nCREATE POLICY \"Users can insert own profile\"\nON profiles FOR INSERT WITH CHECK (auth.uid() = id);\n",[32,174,172],{"__ignoreMap":90},[55,176,178],{"id":177},"posts-with-author","Posts with Author",[82,180,183],{"className":181,"code":182,"language":87},[85],"-- Anyone can read published posts\nCREATE POLICY \"Published posts are public\"\nON posts FOR SELECT USING (status = 'published');\n\n-- Authors can read their own drafts\nCREATE POLICY \"Authors can view own drafts\"\nON posts FOR SELECT USING (auth.uid() = author_id);\n\n-- Only authors can update their posts\nCREATE POLICY \"Authors can update own posts\"\nON posts FOR UPDATE USING (auth.uid() = author_id);\n\n-- Only authors can delete their posts\nCREATE POLICY \"Authors can delete own posts\"\nON posts FOR DELETE USING (auth.uid() = author_id);\n",[32,184,182],{"__ignoreMap":90},[55,186,188],{"id":187},"private-messages","Private Messages",[82,190,193],{"className":191,"code":192,"language":87},[85],"-- Users can read messages they sent or received\nCREATE POLICY \"Users can view own messages\"\nON messages FOR SELECT\nUSING (auth.uid() = sender_id OR auth.uid() = recipient_id);\n\n-- Users can only send messages as themselves\nCREATE POLICY \"Users can send messages\"\nON messages FOR INSERT\nWITH CHECK (auth.uid() = sender_id);\n",[32,194,192],{"__ignoreMap":90},[46,196,198],{"id":197},"common-mistakes","Common Mistakes",[200,201,202,213,219,225],"ul",{},[66,203,204,208,209,212],{},[205,206,207],"strong",{},"Using \"allow all\" policies:"," ",[32,210,211],{},"USING (true)"," for SELECT/UPDATE/DELETE exposes data",[66,214,215,218],{},[205,216,217],{},"Forgetting INSERT policies:"," Users might be able to insert data for other users",[66,220,221,224],{},[205,222,223],{},"Not testing policies:"," Always test with different user IDs",[66,226,227,230],{},[205,228,229],{},"Mixing up USING vs WITH CHECK:"," USING is for read, WITH CHECK is for write",[37,232,233,236],{},[19,234,235],{},"Never Deploy With These Rules",[82,237,240],{"className":238,"code":239,"language":87},[85],"-- DANGEROUS: Allows anyone to do anything\nCREATE POLICY \"Allow all\" ON table FOR ALL USING (true);\n",[32,241,239],{"__ignoreMap":90},[46,243,245],{"id":244},"how-to-verify-rls-is-working","How to Verify RLS is Working",[63,247,248,251,254,257],{},[66,249,250],{},"Open browser DevTools",[66,252,253],{},"Look at Network tab for Supabase API calls",[66,255,256],{},"Note the response - you should only see your own data",[66,258,259],{},"Try modifying the request to fetch other user's data - should fail",[261,262,263,269,274],"related-articles",{},[264,265],"related-card",{"description":266,"href":267,"title":268},"Complete guide to configuring environment variables in Vercel. Set up secrets for production, preview, and development e","/blog/how-to/vercel-env-vars","How to Set Up Vercel Environment Variables",[264,270],{"description":271,"href":272,"title":273},"Step-by-step guide to adding security headers on Vercel. Configure via vercel.json, Next.js middleware, and edge functio","/blog/how-to/vercel-headers","How to Configure Security Headers on Vercel",[264,275],{"description":276,"href":277,"title":278},"Step-by-step guide to input validation with Zod. Schema definition, API validation, form validation with React Hook Form","/blog/how-to/zod-validation","How to Validate Input with Zod",{"title":90,"searchDepth":280,"depth":280,"links":281},2,[282,290,295,296],{"id":48,"depth":280,"text":49,"children":283},[284,286,287,288,289],{"id":57,"depth":285,"text":58},3,{"id":96,"depth":285,"text":97},{"id":121,"depth":285,"text":122},{"id":137,"depth":285,"text":138},{"id":150,"depth":285,"text":151},{"id":163,"depth":280,"text":164,"children":291},[292,293,294],{"id":167,"depth":285,"text":168},{"id":177,"depth":285,"text":178},{"id":187,"depth":285,"text":188},{"id":197,"depth":280,"text":198},{"id":244,"depth":280,"text":245},"how-to","2026-01-23","Step-by-step guide to setting up Row Level Security in Supabase. Enable RLS, write policies, test access, and avoid common mistakes that expose your data.",false,"md",null,"yellow",{},true,"Step-by-step guide to Supabase RLS. Enable, write policies, test access.","/blog/how-to/setup-supabase-rls","[object Object]","HowTo",{"title":5,"description":299},{"loc":307},"blog/how-to/setup-supabase-rls",[],"summary_large_image","hkuEsEpqQi5Xph5_5Hdp038-QYT5rNV9T5Kkn-7ENJc",1775843927717]