[{"data":1,"prerenderedAt":1108},["ShallowReactive",2],{"blog-how-to/supabase-table-not-showing-in-api":3},{"id":4,"title":5,"body":6,"category":1079,"date":1080,"dateModified":1080,"description":1081,"draft":1082,"extension":1083,"faq":1084,"featured":1082,"headerVariant":1093,"image":1094,"keywords":1095,"meta":1096,"navigation":668,"ogDescription":1097,"ogTitle":1094,"path":1098,"readTime":1099,"schemaOrg":1100,"schemaType":1101,"seo":1102,"sitemap":1103,"stem":1104,"tags":1105,"twitterCard":1106,"__hash__":1107},"blog/blog/how-to/supabase-table-not-showing-in-api.md","Supabase Table Not Showing Up in API (2026): The Grants Fix",{"type":7,"value":8,"toc":1070},"minimark",[9,18,21,64,69,72,180,183,189,248,253,289,353,361,365,390,393,441,444,455,463,467,473,598,605,615,633,636,640,643,696,754,783,841,854,858,861,873,888,891,894,901,905,911,927,933,944,966,970,973,980,983,1039,1058,1066],[10,11,12,13,17],"p",{},"You created a table in the Supabase dashboard, called ",[14,15,16],"code",{},".from('orders').select()",", and got back nothing. No rows, no obvious crash, just an empty result and an error object your code probably swallowed. The table is right there in the table editor.",[10,19,20],{},"Two different failures produce that symptom, and they have opposite fixes. Log the actual error before you touch anything.",[22,23,24],"tldr",{},[10,25,26,27,30,31,34,35,38,39,42,43,47,48,51,52,55,56,59,60,63],{},"Since May 30, 2026, new Supabase projects stop granting ",[14,28,29],{},"anon",", ",[14,32,33],{},"authenticated"," and ",[14,36,37],{},"service_role"," access to new ",[14,40,41],{},"public"," tables automatically. A missing grant returns ",[44,45,46],"strong",{},"42501 permission denied for table",", and the fix is an explicit ",[14,49,50],{},"GRANT",". A missing table in the schema cache returns ",[44,53,54],{},"PGRST205",", which is a schema or cache problem instead. Existing projects get the new behaviour on ",[44,57,58],{},"October 30, 2026",". Do not fix it with ",[14,61,62],{},"GRANT ALL ON ALL TABLES IN SCHEMA public TO anon",", which is the answer you'll find most often and the one that opens your whole database.",[65,66,68],"h2",{"id":67},"read-the-error-code-first","Read the error code first",[10,70,71],{},"The Supabase JavaScript client returns errors instead of throwing them, which is why so many people see \"no data\" and never see the reason. Print the whole object.",[73,74,76],"code-block",{"label":75},"src/lib/orders.js",[77,78,83],"pre",{"className":79,"code":80,"language":81,"meta":82,"style":82},"language-js shiki shiki-themes github-dark","const { data, error } = await supabase.from('orders').select('*')\nif (error) console.error(JSON.stringify(error, null, 2))\n","js","",[14,84,85,144],{"__ignoreMap":82},[86,87,90,94,98,102,104,107,110,113,116,119,123,126,130,133,136,138,141],"span",{"class":88,"line":89},"line",1,[86,91,93],{"class":92},"snl16","const",[86,95,97],{"class":96},"s95oV"," { ",[86,99,101],{"class":100},"sDLfK","data",[86,103,30],{"class":96},[86,105,106],{"class":100},"error",[86,108,109],{"class":96}," } ",[86,111,112],{"class":92},"=",[86,114,115],{"class":92}," await",[86,117,118],{"class":96}," supabase.",[86,120,122],{"class":121},"svObZ","from",[86,124,125],{"class":96},"(",[86,127,129],{"class":128},"sU2Wk","'orders'",[86,131,132],{"class":96},").",[86,134,135],{"class":121},"select",[86,137,125],{"class":96},[86,139,140],{"class":128},"'*'",[86,142,143],{"class":96},")\n",[86,145,147,150,153,155,157,160,163,166,169,172,174,177],{"class":88,"line":146},2,[86,148,149],{"class":92},"if",[86,151,152],{"class":96}," (error) console.",[86,154,106],{"class":121},[86,156,125],{"class":96},[86,158,159],{"class":100},"JSON",[86,161,162],{"class":96},".",[86,164,165],{"class":121},"stringify",[86,167,168],{"class":96},"(error, ",[86,170,171],{"class":100},"null",[86,173,30],{"class":96},[86,175,176],{"class":100},"2",[86,178,179],{"class":96},"))\n",[10,181,182],{},"You'll get one of two shapes.",[10,184,185,188],{},[44,186,187],{},"A grant is missing."," Supabase documents this exact response:",[73,190,192],{"label":191},"42501 response",[77,193,197],{"className":194,"code":195,"language":196,"meta":82,"style":82},"language-json shiki shiki-themes github-dark","{\n  \"code\": \"42501\",\n  \"message\": \"permission denied for table your_table\",\n  \"hint\": \"Grant the required privileges to the current role with: GRANT SELECT ON public.your_table TO anon;\"\n}\n","json",[14,198,199,204,218,231,242],{"__ignoreMap":82},[86,200,201],{"class":88,"line":89},[86,202,203],{"class":96},"{\n",[86,205,206,209,212,215],{"class":88,"line":146},[86,207,208],{"class":100},"  \"code\"",[86,210,211],{"class":96},": ",[86,213,214],{"class":128},"\"42501\"",[86,216,217],{"class":96},",\n",[86,219,221,224,226,229],{"class":88,"line":220},3,[86,222,223],{"class":100},"  \"message\"",[86,225,211],{"class":96},[86,227,228],{"class":128},"\"permission denied for table your_table\"",[86,230,217],{"class":96},[86,232,234,237,239],{"class":88,"line":233},4,[86,235,236],{"class":100},"  \"hint\"",[86,238,211],{"class":96},[86,240,241],{"class":128},"\"Grant the required privileges to the current role with: GRANT SELECT ON public.your_table TO anon;\"\n",[86,243,245],{"class":88,"line":244},5,[86,246,247],{"class":96},"}\n",[10,249,250],{},[44,251,252],{},"PostgREST cannot see the table at all:",[73,254,256],{"label":255},"PGRST205 response",[77,257,259],{"className":194,"code":258,"language":196,"meta":82,"style":82},"{\n  \"code\": \"PGRST205\",\n  \"message\": \"Could not find the table 'public.your_table' in the schema cache\"\n}\n",[14,260,261,265,276,285],{"__ignoreMap":82},[86,262,263],{"class":88,"line":89},[86,264,203],{"class":96},[86,266,267,269,271,274],{"class":88,"line":146},[86,268,208],{"class":100},[86,270,211],{"class":96},[86,272,273],{"class":128},"\"PGRST205\"",[86,275,217],{"class":96},[86,277,278,280,282],{"class":88,"line":220},[86,279,223],{"class":100},[86,281,211],{"class":96},[86,283,284],{"class":128},"\"Could not find the table 'public.your_table' in the schema cache\"\n",[86,286,287],{"class":88,"line":233},[86,288,247],{"class":96},[290,291,292,308],"table",{},[293,294,295],"thead",{},[296,297,298,302,305],"tr",{},[299,300,301],"th",{},"Code",[299,303,304],{},"What it means",[299,306,307],{},"Where the fix goes",[309,310,311,328,340],"tbody",{},[296,312,313,319,322],{},[314,315,316],"td",{},[14,317,318],{},"42501",[314,320,321],{},"Table found, role rejected",[314,323,324,325,327],{},"A ",[14,326,50],{}," in the SQL editor",[296,329,330,334,337],{},[314,331,332],{},[14,333,54],{},[314,335,336],{},"Table invisible to PostgREST",[314,338,339],{},"API settings, schema name, or a cache reload",[296,341,342,347,350],{},[314,343,344],{},[14,345,346],{},"42P01",[314,348,349],{},"Relation does not exist",[314,351,352],{},"Your table name or schema is wrong",[10,354,355,356,162],{},"Everything below assumes 42501. If you got PGRST205, skip to ",[357,358,360],"a",{"href":359},"#pgrst205-is-a-different-problem","the PGRST205 section",[65,362,364],{"id":363},"what-supabase-actually-changed","What Supabase actually changed",[10,366,367,368,370,371,30,373,30,376,34,379,382,383,30,385,34,387,389],{},"Until this year, creating a table in ",[14,369,41],{}," silently handed ",[14,372,135],{},[14,374,375],{},"insert",[14,377,378],{},"update",[14,380,381],{},"delete"," to ",[14,384,29],{},[14,386,33],{},[14,388,37],{},". That default is why so many vibe-coded apps ship with an open database: the table was reachable the moment it existed, and nothing asked you to confirm that.",[10,391,392],{},"Supabase is reversing it. The rollout:",[290,394,395,405],{},[293,396,397],{},[296,398,399,402],{},[299,400,401],{},"Date",[299,403,404],{},"What happens",[309,406,407,415,426,434],{},[296,408,409,412],{},[314,410,411],{},"April 28, 2026",[314,413,414],{},"Opt-in toggle appears at project creation",[296,416,417,420],{},[314,418,419],{},"May 18, 2026",[314,421,422,425],{},[14,423,424],{},"pg_graphql"," no longer enabled by default",[296,427,428,431],{},[314,429,430],{},"May 30, 2026",[314,432,433],{},"New behaviour becomes the default for new projects",[296,435,436,438],{},[314,437,58],{},[314,439,440],{},"Setting applied to all existing projects",[10,442,443],{},"The toggle is the \"Automatically expose new tables\" checkbox on the project creation screen. Unchecked means you're on the new behaviour.",[445,446,447],"info-box",{},[10,448,449,450,454],{},"Existing tables are not touched. Supabase's changelog is explicit: they keep their current grants and stay reachable. October 30 changes what happens to tables you create ",[451,452,453],"em",{},"after"," that date, in projects you already have. If your deploy pipeline creates tables, that's the thing that breaks.",[10,456,457,458,34,460,462],{},"The reason given is that explicit grants are reviewable and greppable, and that ",[14,459,29],{},[14,461,33],{}," need different privileges anyway. That's true, and it's also the first Supabase default change in a while that makes the insecure configuration harder to reach by accident.",[65,464,466],{"id":465},"audit-before-you-grant","Audit before you grant",[10,468,469,470,472],{},"Before adding a grant, find out what your project already looks like. Paste this into the SQL editor. It lists every table in ",[14,471,41],{},", whether row level security is on, and which Data API roles hold which privileges.",[73,474,476],{"label":475},"SQL editor",[77,477,481],{"className":478,"code":479,"language":480,"meta":82,"style":82},"language-sql shiki shiki-themes github-dark","select\n  c.relname as table_name,\n  c.relrowsecurity as rls_enabled,\n  coalesce(\n    string_agg(\n      distinct g.grantee || ':' || g.privilege_type,\n      ', ' order by g.grantee || ':' || g.privilege_type\n    ),\n    '(none)'\n  ) as data_api_grants\nfrom pg_class c\njoin pg_namespace n on n.oid = c.relnamespace\nleft join information_schema.role_table_grants g\n  on g.table_schema = n.nspname\n and g.table_name = c.relname\n and g.grantee in ('anon', 'authenticated')\nwhere n.nspname = 'public'\n  and c.relkind in ('r', 'p')\ngroup by c.relname, c.relrowsecurity\norder by c.relrowsecurity, c.relname;\n","sql",[14,482,483,488,493,498,503,508,514,520,526,532,538,544,550,556,562,568,574,580,586,592],{"__ignoreMap":82},[86,484,485],{"class":88,"line":89},[86,486,487],{},"select\n",[86,489,490],{"class":88,"line":146},[86,491,492],{},"  c.relname as table_name,\n",[86,494,495],{"class":88,"line":220},[86,496,497],{},"  c.relrowsecurity as rls_enabled,\n",[86,499,500],{"class":88,"line":233},[86,501,502],{},"  coalesce(\n",[86,504,505],{"class":88,"line":244},[86,506,507],{},"    string_agg(\n",[86,509,511],{"class":88,"line":510},6,[86,512,513],{},"      distinct g.grantee || ':' || g.privilege_type,\n",[86,515,517],{"class":88,"line":516},7,[86,518,519],{},"      ', ' order by g.grantee || ':' || g.privilege_type\n",[86,521,523],{"class":88,"line":522},8,[86,524,525],{},"    ),\n",[86,527,529],{"class":88,"line":528},9,[86,530,531],{},"    '(none)'\n",[86,533,535],{"class":88,"line":534},10,[86,536,537],{},"  ) as data_api_grants\n",[86,539,541],{"class":88,"line":540},11,[86,542,543],{},"from pg_class c\n",[86,545,547],{"class":88,"line":546},12,[86,548,549],{},"join pg_namespace n on n.oid = c.relnamespace\n",[86,551,553],{"class":88,"line":552},13,[86,554,555],{},"left join information_schema.role_table_grants g\n",[86,557,559],{"class":88,"line":558},14,[86,560,561],{},"  on g.table_schema = n.nspname\n",[86,563,565],{"class":88,"line":564},15,[86,566,567],{}," and g.table_name = c.relname\n",[86,569,571],{"class":88,"line":570},16,[86,572,573],{}," and g.grantee in ('anon', 'authenticated')\n",[86,575,577],{"class":88,"line":576},17,[86,578,579],{},"where n.nspname = 'public'\n",[86,581,583],{"class":88,"line":582},18,[86,584,585],{},"  and c.relkind in ('r', 'p')\n",[86,587,589],{"class":88,"line":588},19,[86,590,591],{},"group by c.relname, c.relrowsecurity\n",[86,593,595],{"class":88,"line":594},20,[86,596,597],{},"order by c.relrowsecurity, c.relname;\n",[10,599,600,601,604],{},"Read the top of the result, not the bottom. The ordering puts ",[14,602,603],{},"rls_enabled = false"," first on purpose.",[10,606,607,608,610,611,614],{},"A row with ",[14,609,603],{}," and anything other than ",[14,612,613],{},"(none)"," in the grants column is readable, and possibly writable, by anyone who has your anon key. That key is compiled into your JavaScript bundle. It is not a secret.",[616,617,618],"danger-box",{},[10,619,620,621,624,625,628,629,632],{},"The row you're looking for looks like ",[14,622,623],{},"profiles | false | anon:SELECT, anon:UPDATE, authenticated:SELECT",". That's every profile in your database available to a stranger with ",[14,626,627],{},"curl",", and an ",[14,630,631],{},"UPDATE"," grant on top. Fix those before you spend another minute on the table that isn't showing up.",[10,634,635],{},"This is the pattern our scanner flags on Supabase-backed apps constantly. The table that's broken today is rarely the dangerous one. The dangerous one has been working fine for months.",[65,637,639],{"id":638},"fix-the-missing-grant","Fix the missing grant",[10,641,642],{},"Do these in order. The order matters, because grants take effect immediately and RLS does not exist until you enable it.",[644,645,647,652,690],"step",{"number":646},"1",[10,648,649],{},[44,650,651],{},"Turn on row level security and write a policy.",[73,653,654],{"label":475},[77,655,657],{"className":478,"code":656,"language":480,"meta":82,"style":82},"alter table public.orders enable row level security;\n\ncreate policy \"users read their own orders\"\n  on public.orders for select\n  to authenticated\n  using (auth.uid() = user_id);\n",[14,658,659,664,670,675,680,685],{"__ignoreMap":82},[86,660,661],{"class":88,"line":89},[86,662,663],{},"alter table public.orders enable row level security;\n",[86,665,666],{"class":88,"line":146},[86,667,669],{"emptyLinePlaceholder":668},true,"\n",[86,671,672],{"class":88,"line":220},[86,673,674],{},"create policy \"users read their own orders\"\n",[86,676,677],{"class":88,"line":233},[86,678,679],{},"  on public.orders for select\n",[86,681,682],{"class":88,"line":244},[86,683,684],{},"  to authenticated\n",[86,686,687],{"class":88,"line":510},[86,688,689],{},"  using (auth.uid() = user_id);\n",[10,691,692,693,695],{},"If you enable RLS with no policy, the table returns zero rows to everyone except ",[14,694,37],{},". That's a safe state, not a broken one, and it's the right thing to have in place before the grant lands.",[644,697,698,703,748],{"number":176},[10,699,700],{},[44,701,702],{},"Grant the minimum each role needs.",[73,704,705],{"label":475},[77,706,708],{"className":478,"code":707,"language":480,"meta":82,"style":82},"-- only if this data is genuinely public\ngrant select on public.orders to anon;\n\n-- the logged-in path\ngrant select, insert, update, delete on public.orders to authenticated;\n\n-- your backend and edge functions\ngrant select, insert, update, delete on public.orders to service_role;\n",[14,709,710,715,720,724,729,734,738,743],{"__ignoreMap":82},[86,711,712],{"class":88,"line":89},[86,713,714],{},"-- only if this data is genuinely public\n",[86,716,717],{"class":88,"line":146},[86,718,719],{},"grant select on public.orders to anon;\n",[86,721,722],{"class":88,"line":220},[86,723,669],{"emptyLinePlaceholder":668},[86,725,726],{"class":88,"line":233},[86,727,728],{},"-- the logged-in path\n",[86,730,731],{"class":88,"line":244},[86,732,733],{},"grant select, insert, update, delete on public.orders to authenticated;\n",[86,735,736],{"class":88,"line":510},[86,737,669],{"emptyLinePlaceholder":668},[86,739,740],{"class":88,"line":516},[86,741,742],{},"-- your backend and edge functions\n",[86,744,745],{"class":88,"line":522},[86,746,747],{},"grant select, insert, update, delete on public.orders to service_role;\n",[10,749,750,751,753],{},"Skip the ",[14,752,29],{}," line unless you can name who should be reading this table while logged out. Most tables in a real app have no answer to that.",[644,755,757,762,772],{"number":756},"3",[10,758,759],{},[44,760,761],{},"Grant sequence usage if you insert.",[10,763,324,764,767,768,771],{},[14,765,766],{},"serial"," or ",[14,769,770],{},"identity"," primary key needs its sequence too, or inserts fail with a second, confusingly similar permission error.",[73,773,774],{"label":475},[77,775,777],{"className":478,"code":776,"language":480,"meta":82,"style":82},"grant usage, select on all sequences in schema public to authenticated;\n",[14,778,779],{"__ignoreMap":82},[86,780,781],{"class":88,"line":89},[86,782,776],{},[644,784,786,791,794,834],{"number":785},"4",[10,787,788],{},[44,789,790],{},"Verify from outside, with no session.",[10,792,793],{},"The dashboard runs queries as a privileged role, so it will happily show you data that your app cannot reach and hide data that a stranger can.",[73,795,797],{"label":796},"Terminal",[77,798,802],{"className":799,"code":800,"language":801,"meta":82,"style":82},"language-bash shiki shiki-themes github-dark","curl -s \"https://YOUR_PROJECT.supabase.co/rest/v1/orders?select=*\" \\\n  -H \"apikey: YOUR_ANON_KEY\" | head -20\n","bash",[14,803,804,817],{"__ignoreMap":82},[86,805,806,808,811,814],{"class":88,"line":89},[86,807,627],{"class":121},[86,809,810],{"class":100}," -s",[86,812,813],{"class":128}," \"https://YOUR_PROJECT.supabase.co/rest/v1/orders?select=*\"",[86,815,816],{"class":100}," \\\n",[86,818,819,822,825,828,831],{"class":88,"line":146},[86,820,821],{"class":100},"  -H",[86,823,824],{"class":128}," \"apikey: YOUR_ANON_KEY\"",[86,826,827],{"class":92}," |",[86,829,830],{"class":121}," head",[86,832,833],{"class":100}," -20\n",[10,835,836,837,840],{},"An empty array ",[14,838,839],{},"[]"," means RLS is doing its job. Rows coming back means anonymous visitors can read this table, and you should be sure you meant that. A 42501 means the grant did not apply to the role you tested.",[842,843,844],"warning-box",{},[10,845,846,847,849,850,853],{},"Re-run that ",[14,848,627],{}," after every policy change, not just the first time. A policy written ",[14,851,852],{},"using (true)"," to \"test something\" is the single most common way a locked table quietly becomes an open one, and nothing in the dashboard will tell you.",[65,855,857],{"id":856},"the-fix-that-breaks-everything","The fix that breaks everything",[10,859,860],{},"Search this error and you will land on some version of this:",[73,862,864],{"label":863},"Do not run this",[77,865,867],{"className":478,"code":866,"language":480,"meta":82,"style":82},"grant all on all tables in schema public to anon, authenticated;\n",[14,868,869],{"__ignoreMap":82},[86,870,871],{"class":88,"line":89},[86,872,866],{},[10,874,875,876,30,878,30,880,34,882,884,885,162],{},"It works. Your table appears in the API immediately. It also hands anonymous visitors ",[14,877,135],{},[14,879,375],{},[14,881,378],{},[14,883,381],{}," on every table in your database, including the ones you never intended to expose, plus every table you create later if you pair it with ",[14,886,887],{},"alter default privileges",[10,889,890],{},"If RLS is off on any of those tables, and on a vibe-coded project it usually is on at least one, that command is a full database exposure. Supabase's own security docs put it plainly: tables exposed through the Data API without RLS can be accessed by any role with matching grants.",[10,892,893],{},"Grants and RLS are separate layers, and people conflate them constantly. A grant decides whether a role can touch the table at all. RLS decides which rows it gets back. When the grant is missing, Postgres rejects the query before RLS is ever consulted, which is why \"permission denied\" shows up even on a table with perfectly good policies.",[895,896,898],"lesson-box",{"title":897},"The mental model",[10,899,900],{},"Grant is the door. RLS is the guest list. Removing the door because someone couldn't get in does not mean the guest list is still being checked.",[65,902,904],{"id":903},"pgrst205-is-a-different-problem","PGRST205 is a different problem",[10,906,907,908,910],{},"If your error code is ",[14,909,54],{},", no amount of granting will help. PostgREST builds a cache of the schemas it's told to expose, and your table is not in it. Three causes, in the order they're worth checking:",[10,912,913,916,917,767,920,923,924,926],{},[44,914,915],{},"The schema isn't exposed."," Tables in a custom schema like ",[14,918,919],{},"app",[14,921,922],{},"billing"," need that schema added under Project Settings > API > Exposed schemas. ",[14,925,41],{}," is exposed by default; nothing else is.",[10,928,929,932],{},[44,930,931],{},"The cache is stale."," PostgREST reloads on DDL changes, but a table created through an external connection or during a busy migration can miss the signal. Force it:",[73,934,935],{"label":475},[77,936,938],{"className":478,"code":937,"language":480,"meta":82,"style":82},"notify pgrst, 'reload schema';\n",[14,939,940],{"__ignoreMap":82},[86,941,942],{"class":88,"line":89},[86,943,937],{},[10,945,946,949,950,953,954,957,958,961,962,965],{},[44,947,948],{},"The name is wrong."," Postgres folds unquoted identifiers to lowercase. A table created as ",[14,951,952],{},"\"Orders\""," with quotes is not the same relation as ",[14,955,956],{},"orders",", and ",[14,959,960],{},".from('orders')"," will never find it. Check the exact ",[14,963,964],{},"relname"," in the audit query above.",[65,967,969],{"id":968},"before-october-30","Before October 30",[10,971,972],{},"Two things worth doing now rather than the week it lands.",[10,974,975,976,979],{},"First, make grants part of your migrations. If you use the Supabase CLI, the create-table migration should carry the ",[14,977,978],{},"enable row level security",", the policy, and the grants in one file. A table definition that doesn't say who can read it is incomplete, and after October 30 it'll be visibly incomplete instead of silently permissive.",[10,981,982],{},"Second, run the audit query and deal with what it shows. Every project that predates this change was built under the old default, which means tables got exposed by creation rather than by decision. The change doesn't clean those up for you. Nothing does.",[984,985,986,1006,1015,1021,1033],"faq-section",{},[987,988,990],"faq-item",{"question":989},"Why is my Supabase table not showing up in the API?",[10,991,992,993,30,995,34,997,999,1000,1002,1003,1005],{},"Since May 30, 2026, new Supabase projects no longer grant the ",[14,994,29],{},[14,996,33],{},[14,998,37],{}," roles access to new tables in the ",[14,1001,41],{}," schema automatically. The table exists in Postgres, but the Data API role has no privilege on it, so PostgREST returns 42501 permission denied. You fix it with an explicit ",[14,1004,50],{}," for each role that needs access. If instead you see PGRST205, the table is not visible to PostgREST at all, which is a different problem: an unexposed schema or a stale schema cache.",[987,1007,1009],{"question":1008},"What is the difference between Supabase error 42501 and PGRST205?",[10,1010,1011,1012,1014],{},"42501 is a Postgres error meaning permission denied for that table. PostgREST found the table and the role was rejected, so the fix is a ",[14,1013,50],{},". PGRST205 comes from PostgREST itself and means it could not find the table in its schema cache. That points at a table in a schema you have not exposed under API settings, a typo in the table name, or a cache that has not reloaded yet.",[987,1016,1018],{"question":1017},"When does the Supabase grants change hit my existing project?",[10,1019,1020],{},"October 30, 2026. Supabase applies the setting to all existing projects on that date. Tables you already have keep their current grants and stay reachable. Tables you create after the change need explicit grants, so any migration or dashboard flow that assumed automatic exposure stops working from that point.",[987,1022,1024],{"question":1023},"Is granting to anon safe?",[10,1025,1026,1027,1029,1030,1032],{},"Only when row level security is on and a policy limits what ",[14,1028,29],{}," can read. Grants and RLS are separate layers. A grant decides whether a role can touch the table at all, RLS decides which rows it gets back. A table with a select grant to ",[14,1031,29],{}," and RLS disabled returns every row to anyone holding your anon key, which is public in your JavaScript bundle.",[987,1034,1036],{"question":1035},"Should I run GRANT ALL ON ALL TABLES IN SCHEMA public TO anon?",[10,1037,1038],{},"No. That single command is the most common answer you will find, and it undoes the entire point of the change. It hands anonymous visitors select, insert, update and delete on every table you have, including the ones you never meant to expose. Grant per table, per role, with the smallest privilege that works.",[1040,1041,1042,1048,1053],"related-articles",{},[1043,1044],"related-card",{"description":1045,"href":1046,"title":1047},"Add RLS to an existing Supabase app without locking out users. Audit tables, write policies first, then enable atomically.","/blog/how-to/add-rls-to-supabase","How to Add Row Level Security to Supabase",[1043,1049],{"description":1050,"href":1051,"title":1052},"What anon, authenticated and service_role actually are, and how to give each one the least privilege it needs.","/blog/how-to/postgresql-roles","PostgreSQL Roles and Permissions",[1043,1054],{"description":1055,"href":1056,"title":1057},"24-item checklist covering RLS, API key handling, storage rules, and database security for Supabase apps.","/blog/checklists/supabase-security-checklist","Supabase Security Checklist",[1059,1060,1063],"cta-box",{"href":1061,"label":1062},"/","Scan Your Supabase App Free",[10,1064,1065],{},"Find out which of your tables answer to an anonymous request before someone else does. A CheckYourVibe scan checks your live endpoints from the outside, the same way an attacker would.",[1067,1068,1069],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}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);}",{"title":82,"searchDepth":146,"depth":146,"links":1071},[1072,1073,1074,1075,1076,1077,1078],{"id":67,"depth":146,"text":68},{"id":363,"depth":146,"text":364},{"id":465,"depth":146,"text":466},{"id":638,"depth":146,"text":639},{"id":856,"depth":146,"text":857},{"id":903,"depth":146,"text":904},{"id":968,"depth":146,"text":969},"how-to","2026-08-03","Supabase stopped auto-exposing new tables to the Data API. Tell a missing grant from a stale schema cache, and fix it without opening your database.",false,"md",[1085,1087,1089,1090,1092],{"question":989,"answer":1086},"Since May 30, 2026, new Supabase projects no longer grant the anon, authenticated and service_role roles access to new tables in the public schema automatically. The table exists in Postgres, but the Data API role has no privilege on it, so PostgREST returns 42501 permission denied. You fix it with an explicit GRANT for each role that needs access. If instead you see PGRST205, the table is not visible to PostgREST at all, which is a different problem: an unexposed schema or a stale schema cache.",{"question":1008,"answer":1088},"42501 is a Postgres error meaning permission denied for that table. PostgREST found the table and the role was rejected, so the fix is a GRANT. PGRST205 comes from PostgREST itself and means it could not find the table in its schema cache. That points at a table in a schema you have not exposed under API settings, a typo in the table name, or a cache that has not reloaded yet.",{"question":1017,"answer":1020},{"question":1023,"answer":1091},"Only when row level security is on and a policy limits what anon can read. Grants and RLS are separate layers. A grant decides whether a role can touch the table at all, RLS decides which rows it gets back. A table with a select grant to anon and RLS disabled returns every row to anyone holding your anon key, which is public in your JavaScript bundle.",{"question":1035,"answer":1038},"yellow",null,"supabase table not showing up in api, supabase table not exposed data api, supabase 42501 permission denied for table, supabase pgrst205 schema cache, supabase grant anon authenticated, supabase data api grants october 2026, supabase table not in schema cache",{},"Your new Supabase table returns nothing from the Data API. Read the error code first, grant the exact privilege the role needs, and check RLS before you do.","/blog/how-to/supabase-table-not-showing-in-api","11 min read","[object Object]","HowTo",{"title":5,"description":1081},{"loc":1098},"blog/how-to/supabase-table-not-showing-in-api",[],"summary_large_image","hJ9OMfVw4q5nw5dJoUiihTc3gjS_FARBFmGygBFKIPs",1785794502945]