[{"data":1,"prerenderedAt":601},["ShallowReactive",2],{"blog-how-to/add-rls-to-lovable":3},{"id":4,"title":5,"body":6,"category":570,"date":571,"dateModified":571,"description":572,"draft":573,"extension":574,"faq":575,"featured":573,"headerVariant":586,"image":587,"keywords":588,"meta":589,"navigation":157,"ogDescription":590,"ogTitle":587,"path":591,"readTime":592,"schemaOrg":593,"schemaType":594,"seo":595,"sitemap":596,"stem":597,"tags":598,"twitterCard":599,"__hash__":600},"blog/blog/how-to/add-rls-to-lovable.md","How to Add Row Level Security to Your Lovable App (2026)",{"type":7,"value":8,"toc":562},"minimark",[9,13,22,25,35,40,48,111,114,124,128,135,184,198,201,205,208,309,326,330,333,374,380,390,394,397,407,421,427,441,445,464,470,488,531,550,558],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,16,17,21],"p",{},"Lovable connects to Supabase using the anon key, and that key lives in every user's browser. Without Row Level Security, any signed-in user can run ",[18,19,20],"code",{},"SELECT * FROM your_table"," and get every row, not just their own. CheckYourVibe sees this as the most common finding in Lovable+Supabase apps. Over half of scanned Lovable projects have at least one table with RLS disabled.",[14,23,24],{},"Fixing it takes about 10 minutes of SQL.",[26,27,28],"tldr",{},[14,29,30,31,34],{},"Enable RLS on every Supabase table your Lovable app uses, then add a ",[18,32,33],{},"USING (auth.uid() = user_id)"," policy for each one. Without policies, enabling RLS blocks all access. Add the policy first. Run the audit query below to find every table that's currently unprotected.",[36,37,39],"h2",{"id":38},"step-1-audit-which-tables-have-rls-disabled","Step 1: Audit Which Tables Have RLS Disabled",[14,41,42,43,47],{},"Open Supabase Dashboard, go to ",[44,45,46],"strong",{},"SQL Editor",", and run:",[49,50,52],"code-block",{"label":51},"Find tables with RLS off",[53,54,59],"pre",{"className":55,"code":56,"language":57,"meta":58,"style":58},"language-sql shiki shiki-themes github-light github-dark","SELECT\n  schemaname,\n  tablename,\n  rowsecurity\nFROM pg_tables\nWHERE schemaname = 'public'\n  AND rowsecurity = false\nORDER BY tablename;\n","sql","",[18,60,61,69,75,81,87,93,99,105],{"__ignoreMap":58},[62,63,66],"span",{"class":64,"line":65},"line",1,[62,67,68],{},"SELECT\n",[62,70,72],{"class":64,"line":71},2,[62,73,74],{},"  schemaname,\n",[62,76,78],{"class":64,"line":77},3,[62,79,80],{},"  tablename,\n",[62,82,84],{"class":64,"line":83},4,[62,85,86],{},"  rowsecurity\n",[62,88,90],{"class":64,"line":89},5,[62,91,92],{},"FROM pg_tables\n",[62,94,96],{"class":64,"line":95},6,[62,97,98],{},"WHERE schemaname = 'public'\n",[62,100,102],{"class":64,"line":101},7,[62,103,104],{},"  AND rowsecurity = false\n",[62,106,108],{"class":64,"line":107},8,[62,109,110],{},"ORDER BY tablename;\n",[14,112,113],{},"Every table in the results is wide open. Write down the list. You'll enable RLS on each one in the next step.",[115,116,117],"warning-box",{},[14,118,119,120,123],{},"Enabling RLS on a table with ",[44,121,122],{},"no policies"," blocks all reads and writes immediately. Don't enable RLS until you have the policy ready. Do both in the same SQL transaction.",[36,125,127],{"id":126},"step-2-enable-rls-and-add-a-read-policy-together","Step 2: Enable RLS and Add a Read Policy Together",[14,129,130,131,134],{},"For a table called ",[18,132,133],{},"profiles"," where each row belongs to a user:",[49,136,138],{"label":137},"Enable RLS + read policy",[53,139,141],{"className":55,"code":140,"language":57,"meta":58,"style":58},"-- Enable RLS\nALTER TABLE profiles ENABLE ROW LEVEL SECURITY;\n\n-- Allow users to read only their own row\nCREATE POLICY \"Users can read own profile\"\nON profiles\nFOR SELECT\nUSING (auth.uid() = user_id);\n",[18,142,143,148,153,159,164,169,174,179],{"__ignoreMap":58},[62,144,145],{"class":64,"line":65},[62,146,147],{},"-- Enable RLS\n",[62,149,150],{"class":64,"line":71},[62,151,152],{},"ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;\n",[62,154,155],{"class":64,"line":77},[62,156,158],{"emptyLinePlaceholder":157},true,"\n",[62,160,161],{"class":64,"line":83},[62,162,163],{},"-- Allow users to read only their own row\n",[62,165,166],{"class":64,"line":89},[62,167,168],{},"CREATE POLICY \"Users can read own profile\"\n",[62,170,171],{"class":64,"line":95},[62,172,173],{},"ON profiles\n",[62,175,176],{"class":64,"line":101},[62,177,178],{},"FOR SELECT\n",[62,180,181],{"class":64,"line":107},[62,182,183],{},"USING (auth.uid() = user_id);\n",[14,185,186,189,190,193,194,197],{},[18,187,188],{},"auth.uid()"," returns the UUID of the currently authenticated user. The ",[18,191,192],{},"USING"," clause filters which rows they can see. If ",[18,195,196],{},"user_id"," is the column that stores the owner, this one policy protects the table for reads.",[14,199,200],{},"Repeat this pattern for every table in your audit list.",[36,202,204],{"id":203},"step-3-add-write-policies","Step 3: Add Write Policies",[14,206,207],{},"Read-only is a start, but users also need to insert, update, and delete their own data:",[49,209,211],{"label":210},"Insert, update, delete policies",[53,212,214],{"className":55,"code":213,"language":57,"meta":58,"style":58},"-- Allow users to insert rows for themselves\nCREATE POLICY \"Users can insert own data\"\nON profiles\nFOR INSERT\nWITH CHECK (auth.uid() = user_id);\n\n-- Allow users to update only their own rows\nCREATE POLICY \"Users can update own data\"\nON profiles\nFOR UPDATE\nUSING (auth.uid() = user_id)\nWITH CHECK (auth.uid() = user_id);\n\n-- Allow users to delete only their own rows\nCREATE POLICY \"Users can delete own data\"\nON profiles\nFOR DELETE\nUSING (auth.uid() = user_id);\n",[18,215,216,221,226,230,235,240,244,249,254,259,265,271,276,281,287,293,298,304],{"__ignoreMap":58},[62,217,218],{"class":64,"line":65},[62,219,220],{},"-- Allow users to insert rows for themselves\n",[62,222,223],{"class":64,"line":71},[62,224,225],{},"CREATE POLICY \"Users can insert own data\"\n",[62,227,228],{"class":64,"line":77},[62,229,173],{},[62,231,232],{"class":64,"line":83},[62,233,234],{},"FOR INSERT\n",[62,236,237],{"class":64,"line":89},[62,238,239],{},"WITH CHECK (auth.uid() = user_id);\n",[62,241,242],{"class":64,"line":95},[62,243,158],{"emptyLinePlaceholder":157},[62,245,246],{"class":64,"line":101},[62,247,248],{},"-- Allow users to update only their own rows\n",[62,250,251],{"class":64,"line":107},[62,252,253],{},"CREATE POLICY \"Users can update own data\"\n",[62,255,257],{"class":64,"line":256},9,[62,258,173],{},[62,260,262],{"class":64,"line":261},10,[62,263,264],{},"FOR UPDATE\n",[62,266,268],{"class":64,"line":267},11,[62,269,270],{},"USING (auth.uid() = user_id)\n",[62,272,274],{"class":64,"line":273},12,[62,275,239],{},[62,277,279],{"class":64,"line":278},13,[62,280,158],{"emptyLinePlaceholder":157},[62,282,284],{"class":64,"line":283},14,[62,285,286],{},"-- Allow users to delete only their own rows\n",[62,288,290],{"class":64,"line":289},15,[62,291,292],{},"CREATE POLICY \"Users can delete own data\"\n",[62,294,296],{"class":64,"line":295},16,[62,297,173],{},[62,299,301],{"class":64,"line":300},17,[62,302,303],{},"FOR DELETE\n",[62,305,307],{"class":64,"line":306},18,[62,308,183],{},[14,310,311,314,315,318,319,322,323,325],{},[18,312,313],{},"INSERT"," and ",[18,316,317],{},"UPDATE"," use ",[18,320,321],{},"WITH CHECK"," (what they're allowed to write) in addition to ",[18,324,192],{}," (what they're allowed to touch).",[36,327,329],{"id":328},"step-4-handle-tables-without-a-user_id-column","Step 4: Handle Tables Without a user_id Column",[14,331,332],{},"Some Lovable apps have reference tables (categories, lookup lists, config rows) that should be readable by anyone but writable only by admins. For those:",[49,334,336],{"label":335},"Public read, no writes",[53,337,339],{"className":55,"code":338,"language":57,"meta":58,"style":58},"ALTER TABLE categories ENABLE ROW LEVEL SECURITY;\n\n-- Anyone (including unauthenticated) can read\nCREATE POLICY \"Public read access\"\nON categories\nFOR SELECT\nUSING (true);\n",[18,340,341,346,350,355,360,365,369],{"__ignoreMap":58},[62,342,343],{"class":64,"line":65},[62,344,345],{},"ALTER TABLE categories ENABLE ROW LEVEL SECURITY;\n",[62,347,348],{"class":64,"line":71},[62,349,158],{"emptyLinePlaceholder":157},[62,351,352],{"class":64,"line":77},[62,353,354],{},"-- Anyone (including unauthenticated) can read\n",[62,356,357],{"class":64,"line":83},[62,358,359],{},"CREATE POLICY \"Public read access\"\n",[62,361,362],{"class":64,"line":89},[62,363,364],{},"ON categories\n",[62,366,367],{"class":64,"line":95},[62,368,178],{},[62,370,371],{"class":64,"line":101},[62,372,373],{},"USING (true);\n",[14,375,376,379],{},[18,377,378],{},"USING (true)"," means the policy always passes. You're not restricting reads, but RLS is still on, so any missing write policy will block unintended inserts.",[381,382,383],"tip-box",{},[14,384,385,386,389],{},"If your Lovable app has a multi-user or team model, your policies get more complex. The ",[18,387,388],{},"supabase-rls-policies"," post has examples for teams, admins, and shared data.",[36,391,393],{"id":392},"step-5-verify-rls-is-active","Step 5: Verify RLS Is Active",[14,395,396],{},"Two ways to check:",[14,398,399,402,403,406],{},[44,400,401],{},"In Supabase Dashboard:"," Go to ",[44,404,405],{},"Table Editor",", click a table, and look for the green \"RLS enabled\" badge at the top.",[14,408,409,412,413,416,417,420],{},[44,410,411],{},"With the audit query:"," Re-run the Step 1 query. Every table that had ",[18,414,415],{},"rowsecurity = false"," should now return ",[18,418,419],{},"true",".",[14,422,423,426],{},[44,424,425],{},"With CheckYourVibe:"," Run a scan on your app URL. The scanner checks for Supabase RLS coverage and flags any unprotected tables as a critical finding.",[428,429,431],"step",{"number":430},"6",[14,432,433,436,437,440],{},[44,434,435],{},"Re-test your Lovable app end-to-end."," Log in as two different test users and confirm that User A cannot read User B's data. If something breaks, you likely have a missing policy. Check the Supabase Logs tab under ",[44,438,439],{},"API"," for the specific query that failed.",[36,442,444],{"id":443},"common-mistakes","Common Mistakes",[115,446,447],{},[14,448,449,452,453,455,456,459,460,463],{},[44,450,451],{},"Missing user_id column."," If Lovable didn't generate a ",[18,454,196],{}," column on a table, you can't use ",[18,457,458],{},"auth.uid() = user_id",". Add the column first: ",[18,461,462],{},"ALTER TABLE your_table ADD COLUMN user_id uuid REFERENCES auth.users(id);"," then backfill it.",[14,465,466,469],{},[44,467,468],{},"Forgetting the storage bucket."," Supabase Storage has its own RLS system separate from tables. If your Lovable app uploads files, check Storage Policies too.",[14,471,472,475,476,479,480,483,484,487],{},[44,473,474],{},"Using service_role in the client."," If your Lovable app has the ",[18,477,478],{},"service_role"," key in the frontend (starts with ",[18,481,482],{},"eyJhbGci"," and decodes to ",[18,485,486],{},"\"role\": \"service_role\"","), RLS won't protect you at all. Service role bypasses RLS by design. Move it to a server-side function immediately.",[489,490,491,498,504,519,525],"faq-section",{},[492,493,495],"faq-item",{"question":494},"Does Lovable enable RLS automatically?",[14,496,497],{},"No. Lovable generates the Supabase schema but leaves RLS off by default. You enable it manually in the Supabase SQL Editor on each table.",[492,499,501],{"question":500},"What happens if I skip RLS in my Lovable app?",[14,502,503],{},"Any signed-in user can query any row in your database directly using the anon key that's visible in their browser. They don't need to find a bug in your code, they just call the Supabase REST API directly.",[492,505,507],{"question":506},"Can I use auth.uid() in RLS policies with Lovable?",[14,508,509,510,512,513,515,516,518],{},"Yes. Lovable uses Supabase Auth, so ",[18,511,188],{}," returns the current user's UUID for every authenticated request. Your policy just needs ",[18,514,33],{}," where ",[18,517,196],{}," is the ownership column.",[492,520,522],{"question":521},"My app broke after enabling RLS. What happened?",[14,523,524],{},"You enabled RLS before creating any policies. RLS with zero policies blocks all access. Add the SELECT policy first, confirm reads work, then add INSERT/UPDATE/DELETE policies one at a time.",[492,526,528],{"question":527},"How do I test that RLS is actually working?",[14,529,530],{},"Log in as two different users and confirm neither can read the other's data. You can also run a CheckYourVibe scan or use the Supabase API Explorer with the anon role to query a protected table directly.",[532,533,534,540,545],"related-articles",{},[535,536],"related-card",{"description":537,"href":538,"title":539},"Enable RLS, write policies, and test access with this step-by-step Supabase guide.","/blog/how-to/setup-supabase-rls","How to Set Up Supabase Row Level Security (RLS)",[535,541],{"description":542,"href":543,"title":544},"Real policy examples for profiles, posts, teams, and multi-tenant apps.","/blog/how-to/supabase-rls-policies","How to Write Supabase RLS Policies",[535,546],{"description":547,"href":548,"title":549},"Complete security configuration for the Lovable + Supabase stack.","/blog/blueprints/lovable-supabase","Lovable + Supabase Security Blueprint",[551,552,555],"cta-box",{"href":553,"label":554},"/","Start Free Scan",[14,556,557],{},"Scan your Lovable app now to find every table with RLS disabled and other Supabase misconfigurations.",[559,560,561],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":58,"searchDepth":71,"depth":71,"links":563},[564,565,566,567,568,569],{"id":38,"depth":71,"text":39},{"id":126,"depth":71,"text":127},{"id":203,"depth":71,"text":204},{"id":328,"depth":71,"text":329},{"id":392,"depth":71,"text":393},{"id":443,"depth":71,"text":444},"how-to","2026-06-17","Step-by-step guide to enabling Supabase RLS in Lovable apps. Audit every table, write auth.uid() policies, and stop any logged-in user from reading your whole database.",false,"md",[576,578,580,582,584],{"question":494,"answer":577},"No. Lovable generates the Supabase schema but RLS is off by default. You have to enable it manually on each table.",{"question":500,"answer":579},"Any logged-in user can query every row in your database using the Supabase anon key, which is visible in their browser. No code changes needed on their end.",{"question":506,"answer":581},"Yes. Lovable apps use Supabase Auth, so auth.uid() is populated for any signed-in user. Your policy should check auth.uid() = user_id (or whichever column stores the owner).",{"question":521,"answer":583},"Enabling RLS with no policies blocks all access by default. You need at least one SELECT policy before your app can read data again. Add the policy first, then enable RLS.",{"question":527,"answer":585},"Run a CheckYourVibe scan or open Supabase's API explorer, switch to the anon role, and try querying a table. With correct RLS, you should get 0 rows for other users' data.","yellow",null,"lovable rls supabase, row level security lovable, supabase rls lovable app, add rls supabase lovable, lovable supabase security",{},"Enable Supabase RLS in your Lovable app. Audit tables, write policies, and lock down your database in minutes.","/blog/how-to/add-rls-to-lovable","7 min read","[object Object]","HowTo",{"title":5,"description":572},{"loc":591},"blog/how-to/add-rls-to-lovable",[],"summary_large_image","DTweV-t-XoPNZJ1GGkXJZw66TzoP6o7oKn9Wr1waFdk",1784736388718]