[{"data":1,"prerenderedAt":1367},["ShallowReactive",2],{"blog-pt-canceling-statement-due-to-statement-timeout":3,"blog-index-pt":838},{"id":4,"title":5,"body":6,"category":796,"cover":797,"coverAlt":798,"description":799,"draft":800,"extension":801,"faq":802,"image":817,"keywords":818,"meta":826,"navigation":827,"ogTitle":828,"path":829,"published":830,"seo":831,"stem":832,"tldr":833,"updated":830,"__hash__":837},"blog_pt\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout.md","Supabase \"canceling statement due to statement timeout\", explicado",{"type":7,"value":8,"toc":782},"minimark",[9,13,24,27,30,35,38,57,60,64,67,70,148,158,161,167,171,178,194,202,223,226,235,239,246,261,267,278,285,288,292,295,298,404,407,414,424,428,431,439,445,465,470,476,494,511,525,531,537,540,546,558,563,567,570,576,583,589,600,604,607,634,656,664,668,674,683,703,712,729,733,775],[10,11,12],"p",{},"A página do seu app carrega a lista, o indicador gira por alguns segundos e\ndepois nada aparece. No console do navegador, ou num aviso vermelho que o seu\nbuilder colocou, há uma linha:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","canceling statement due to statement timeout\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Você abre a mesma tabela no Supabase e todas as linhas estão lá. Pergunta ao\nbuilder com que fez o app (Lovable, Bolt, v0, Cursor, Claude Code ou Replit)\nqual consulta aquela página executa, cola no SQL Editor, e ela volta num\ninstante.",[10,28,29],{},"O primeiro conselho que você vai achar para \"canceling statement due to\nstatement timeout\" no Supabase é aumentar o limite. Esse limite está fazendo o\ntrabalho dele, e todo visitante do seu app o divide. Antes de aumentar\nqualquer coisa, olhe a política de Row Level Security dessa tabela, a regra que\no Postgres verifica antes de entregar cada linha. Nas medições do próprio\nSupabase, é nessa regra que uma consulta que deveria levar 7 milissegundos leva\n11 segundos.",[31,32,34],"h2",{"id":33},"o-que-significa-canceling-statement-due-to-statement-timeout-no-supabase","O que significa \"canceling statement due to statement timeout\" no Supabase?",[10,36,37],{},"O Postgres, o banco de dados dentro do seu projeto Supabase, parou a consulta\nporque ela durou mais do que o papel que a enviou permite, e desfez o que a\nconsulta tinha feito.",[10,39,40,41,44,45,48,49,52,53,56],{},"A frase vem do próprio Postgres, com o código de erro ",[21,42,43],{},"57014",", que o Postgres\nchama de ",[21,46,47],{},"query_canceled",". O Supabase repassa a frase sem mudanças ao seu app,\nentão o erro que o seu código recebe traz ",[21,50,51],{},"code: '57014'"," e essa frase como\nmensagem. O Postgres usa o mesmo código para ",[21,54,55],{},"canceling statement due to user request",", um cancelamento que alguém pediu, por isso a frase diz mais do que o\nnúmero.",[10,58,59],{},"Pense no seu banco como uma biblioteca, com um balcão e um timer de cozinha.\nCada vez que alguém pede livros, a bibliotecária liga o timer antes de ir às\nestantes, e quanto tempo ele dura depende de quem pede. Quando ele toca, cada\nlivro volta para a estante e o visitante recebe um papel com essa frase. Se o\npedido era para mudar alguma coisa, a mudança também é desfeita.",[31,61,63],{"id":62},"por-que-a-consulta-funciona-no-sql-editor-e-falha-no-meu-app","Por que a consulta funciona no SQL Editor e falha no meu app?",[10,65,66],{},"Porque o SQL Editor pergunta como outro visitante, um sem timer próprio e sem\nregras para verificar.",[10,68,69],{},"Cada pedido chega ao Postgres com um papel, um nome que decide o que o pedido\npode fazer. O guia de timeouts do Supabase lista o limite com que cada papel\ncomeça:",[71,72,73,89],"table",{},[74,75,76],"thead",{},[77,78,79,83,86],"tr",{},[80,81,82],"th",{},"Quem pergunta",[80,84,85],{},"Papel",[80,87,88],{},"Tempo permitido",[90,91,92,106,119,135],"tbody",{},[77,93,94,98,103],{},[95,96,97],"td",{},"Um visitante do seu app sem login",[95,99,100],{},[21,101,102],{},"anon",[95,104,105],{},"3 segundos",[77,107,108,111,116],{},[95,109,110],{},"Um usuário do seu app com login",[95,112,113],{},[21,114,115],{},"authenticated",[95,117,118],{},"8 segundos",[77,120,121,124,129],{},[95,122,123],{},"O seu servidor, com a chave secreta",[95,125,126],{},[21,127,128],{},"service_role",[95,130,131,132],{},"nenhum próprio, então valem os 8 segundos do papel ",[21,133,134],{},"authenticator",[77,136,137,140,145],{},[95,138,139],{},"Você, no dashboard e no SQL Editor",[95,141,142],{},[21,143,144],{},"postgres",[95,146,147],{},"nenhum próprio, com um teto padrão de 2 minutos",[10,149,150,151,153,154,157],{},"O papel do editor tem uma segunda vantagem. O guia de Row Level Security do\nSupabase diz que no Supabase o ",[21,152,144],{}," tem ",[21,155,156],{},"bypassrls",", o atributo do\nPostgres que pula todas as políticas. Então o editor responde sem ler uma regra\nsequer. O pedido do seu app lê cada política da tabela em cada linha que olha,\ncom um timer que toca aos três segundos para um visitante sem login. O editor\ncronometrou uma consulta diferente da que o seu app envia.",[10,159,160],{},"Na biblioteca, você é da equipe. Entra no acervo sem timer e ninguém pede a sua\ncarteirinha. O visitante tem três segundos, e a bibliotecária verifica as\nregras em cada livro pelo caminho.",[162,163],"diagram",{"alt":164,"caption":165,"src":166},"A mesma consulta desenhada como três barras numa escala de tempo. Para postgres a barra vai até o fim sem marcas e termina com um visto. Para authenticated e anon a barra tem uma marca a cada passo; a de authenticated termina com um visto antes da sua linha de 8 segundos, e a de anon é cortada em vermelho na sua linha de 3 segundos.","Uma consulta, três papéis. O papel do editor pula a política e não tem linha para cruzar; um visitante sem login passa por cada verificação e é parado aos três segundos.","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fthree-clocks-1600x720.png",[31,168,170],{"id":169},"encontre-a-consulta-que-foi-cancelada","Encontre a consulta que foi cancelada",[10,172,173,174,177],{},"Procure nos logs do Postgres do seu projeto as palavras ",[21,175,176],{},"statement timeout",", e\nanote qual papel enviou a consulta.",[10,179,180,181,185,186,189,190,193],{},"O guia de timeouts do Supabase traz uma consulta para isso. No dashboard, abra\n",[182,183,184],"strong",{},"Explorer",", escolha ",[182,187,188],{},"Run SQL",", defina ",[182,191,192],{},"Logs"," como origem, escolha um\nintervalo de tempo que cubra a falha e rode esta versão encurtada:",[14,195,200],{"className":196,"code":198,"language":199,"meta":23},[197],"language-sql","select timestamp,\n       log_attributes['parsed.user_name'] as user_name,\n       log_attributes['parsed.query'] as query\nfrom logs\nwhere source = 'postgres_logs'\n  and match(event_message, 'statement timeout')\norder by timestamp desc\nlimit 100;\n","sql",[21,201,198],{"__ignoreMap":23},[10,203,204,205,208,209,211,212,215,216,218,219,222],{},"Um ",[21,206,207],{},"user_name"," igual a ",[21,210,134],{}," quer dizer que o pedido veio pela Data\nAPI, o servidor por onde passa cada chamada ",[21,213,214],{},"supabase.from(…)"," do seu app. A\ntabela de papéis do guia lista ",[21,217,134],{}," como PostgREST, que é esse\nservidor. A coluna ",[21,220,221],{},"query"," é o SQL em que o pedido do seu app se transformou, e\no nome de tabela que aparece ali é a tabela para olhar.",[10,224,225],{},"A página Query Performance do dashboard é o outro lugar onde se costuma olhar,\ne o guia avisa que ela só mostra consultas lentas que terminaram. Uma consulta\ncancelada está nos logs.",[10,227,228,229,234],{},"Se os logs mostram cancelamentos em todas as tabelas ao mesmo tempo, a parte\nlenta não é uma política só, e\n",[230,231,233],"a",{"href":232},"\u002Fblog\u002Fis-supabase-down-or-your-app","distinguir uma queda do Supabase de um problema no seu app","\né por onde começar.",[31,236,238],{"id":237},"meça-como-o-seu-app-executa","Meça como o seu app executa",[10,240,241,242,245],{},"Rode a consulta com o papel do seu app e ",[21,243,244],{},"explain analyze"," na frente, e o\nPostgres mostra quanto tempo ela levou e quantas linhas a política recusou.",[10,247,248,249,252,253,256,257,260],{},"É o método do guia do Supabase sobre desempenho de Row Level Security, dentro\nde ",[21,250,251],{},"begin"," e ",[21,254,255],{},"rollback"," para a troca de papel acabar junto com o bloco. Copie o\nid de um usuário real em ",[182,258,259],{},"Authentication → Users"," no lugar dos zeros:",[14,262,265],{"className":263,"code":264,"language":199,"meta":23},[197],"begin;\nset local role authenticated;\nset local request.jwt.claims to '{\"role\":\"authenticated\", \"sub\":\"00000000-0000-0000-0000-000000000000\"}';\nexplain analyze select * from public.orders;\nrollback;\n",[21,266,264],{"__ignoreMap":23},[10,268,269,270,273,274,277],{},"Duas linhas da saída importam. ",[21,271,272],{},"Execution Time"," é o número para comparar com 3\ne 8 segundos. ",[21,275,276],{},"Rows Removed by Filter"," conta as linhas que o Postgres leu e a\npolítica recusou, e o guia do Supabase a chama de sinal a observar: uma política\nque descarta a maior parte da tabela a cada leitura é uma política cuja coluna\nde filtro precisa de um índice.",[10,279,280,281,284],{},"Para medir o que um visitante sem login recebe, escreva ",[21,282,283],{},"set local role anon;","\ne tire a linha dos claims.",[10,286,287],{},"O mesmo guia sugere rodar a consulta uma vez com Row Level Security ligado e\noutra desligado, para ver se o custo está na política. Ele também diz para\nfazer isso só fora da produção, porque desligar expõe cada linha. Num app no\nar, compare a política com a versão reescrita dela.",[31,289,291],{"id":290},"como-uma-política-pode-custar-segundos","Como uma política pode custar segundos?",[10,293,294],{},"O Postgres verifica a política em cada linha que a consulta lê, e uma chamada\nde função dentro da política roda de novo para cada uma dessas linhas.",[10,296,297],{},"O Supabase publicou medições disso, numa tabela de 100.000 linhas. Quatro\ndelas, o jeito lento e o rápido:",[71,299,300,318],{},[74,301,302],{},[77,303,304,307,310,313,316],{},[80,305,306],{},"O que a política verifica",[80,308,309],{},"Escrita como",[80,311,312],{},"Levou",[80,314,315],{},"Reescrita como",[80,317,312],{},[90,319,320,341,362,383],{},[77,321,322,325,330,333,338],{},[95,323,324],{},"Linhas que pertencem ao usuário com login",[95,326,327],{},[21,328,329],{},"auth.uid() = user_id",[95,331,332],{},"179 ms",[95,334,335],{},[21,336,337],{},"(select auth.uid()) = user_id",[95,339,340],{},"9 ms",[77,342,343,346,350,353,359],{},[95,344,345],{},"A mesma regra, sem índice na coluna",[95,347,348],{},[21,349,329],{},[95,351,352],{},"171 ms",[95,354,355,356],{},"a mesma, com um índice em ",[21,357,358],{},"user_id",[95,360,361],{},"menos de 0,1 ms",[77,363,364,367,372,375,380],{},[95,365,366],{},"Uma checagem de admin que lê outra tabela",[95,368,369],{},[21,370,371],{},"is_admin()",[95,373,374],{},"11.000 ms",[95,376,377],{},[21,378,379],{},"(select is_admin())",[95,381,382],{},"7 ms",[77,384,385,388,393,396,401],{},[95,386,387],{},"Um papel buscado em outra tabela",[95,389,390],{},[21,391,392],{},"has_role() = role",[95,394,395],{},"178.000 ms",[95,397,398],{},[21,399,400],{},"(select has_role()) = role",[95,402,403],{},"12 ms",[10,405,406],{},"As duas primeiras são lentas e ainda assim ficam abaixo de três segundos nessa\ntabela. As duas últimas passam de qualquer limite que um pedido de app tenha.\nUma função helper que lê uma segunda tabela, do tipo que se escreve para saber\nse alguém é admin, é chamada uma vez para cada linha da primeira, então nessa\ntabela ela leu a segunda 100.000 vezes.",[10,408,409,410,413],{},"Na biblioteca, esse helper é a bibliotecária indo até o escritório da entrada\nperguntar se você é da equipe, uma vez para cada livro da estante. Envolvê-lo\nem ",[21,411,412],{},"(select …)"," é perguntar uma vez e anotar a resposta no papel.",[10,415,416,417],{},"O Performance Advisor do Supabase pega parte disso. A regra dele chamada Auth\nRLS Initialization Plan aponta uma política que \"re-evaluates\ncurrent_setting() or auth.",[418,419,420,421,423],"function",{},"() for each row\". Um helper seu, como\n",[21,422,371],{},", fica fora dessa descrição, então uma página do advisor sem\nalertas não verificou os seus helpers. Leia você mesmo as políticas da tabela\nprocurando qualquer chamada de função que não esteja envolvida.",[31,425,427],{"id":426},"conserte-nesta-ordem","Conserte nesta ordem",[10,429,430],{},"Envolva as chamadas de função, crie um índice na coluna que a política compara\ne depois nomeie o papel. Cada passo é um trecho curto de SQL que você pode rodar\nno editor ou passar para o seu builder.",[10,432,433],{},[182,434,435,436,438],{},"1. Envolva cada chamada de função em ",[21,437,412],{},".",[14,440,443],{"className":441,"code":442,"language":199,"meta":23},[197],"alter policy \"read own orders\" on public.orders\n  using ( (select auth.uid()) = user_id );\n",[21,444,442],{"__ignoreMap":23},[10,446,447,450,451,454,455,459,460,464],{},[21,448,449],{},"alter policy"," mantém o nome e o papel da política e troca a condição. Use o\nnome da sua política e a coluna da sua tabela, e faça o mesmo com um helper:\n",[21,452,453],{},"(select private.is_admin())",". O Supabase põe uma condição: isso só funciona\npara um valor que não muda de uma linha para outra. Por que os parênteses fazem\ndiferença está em\n",[230,456,458],{"href":457},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","o guia para ligar o Row Level Security",",\ne um helper escrito para\n",[230,461,463],{"href":462},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","resolver um erro de recursão infinita","\né exatamente o tipo que precisa deles.",[10,466,467],{},[182,468,469],{},"2. Crie um índice na coluna que a política compara.",[14,471,474],{"className":472,"code":473,"language":199,"meta":23},[197],"create index orders_user_id_idx on public.orders (user_id);\n",[21,475,473],{"__ignoreMap":23},[10,477,478,479,482,483,485,486,489,490,493],{},"O guia do Supabase acrescenta um porém. Uma coluna só conta como indexada\nquando vem primeiro no índice, então uma tabela cuja chave primária é\n",[21,480,481],{},"(team_id, user_id)"," não tem índice em ",[21,484,358],{},". Numa tabela grande que recebe\nescritas enquanto você trabalha, a documentação do Postgres diz que um\n",[21,487,488],{},"create index"," comum trava a tabela contra escritas até terminar.\n",[21,491,492],{},"create index concurrently"," cria o índice sem essa trava, e precisa rodar como\num comando sozinho, fora de uma transação.",[10,495,496,499,500,503,504,507,508,510],{},[182,497,498],{},"3. Nomeie o papel a que a política se destina."," Uma política escrita\n",[21,501,502],{},"to authenticated"," nunca roda para um visitante sem login. Nas medições do\nSupabase, um pedido sem login contra uma política sem ",[21,505,506],{},"to"," levou 170 ms, e com\n",[21,509,502],{}," menos de 0,1 ms.",[10,512,513,516,517,520,521,524],{},[182,514,515],{},"4. Filtre também no pedido."," Uma política funciona como um ",[21,518,519],{},"where","\ninvisível em cada consulta, e o guia do Supabase recomenda repeti-lo no pedido\ndo seu app, ",[21,522,523],{},".eq('user_id', userId)",", porque o Postgres consegue planejar uma\nconsulta mais rápida com ele. Nas medições deles, isso levou uma consulta de\n171 ms para 9.",[10,526,527,530],{},[182,528,529],{},"5. Tire o join de uma política de equipe."," Uma política que compara cada\nlinha com uma tabela de membros faz essa busca linha por linha:",[14,532,535],{"className":533,"code":534,"language":199,"meta":23},[197],"using ( (select auth.uid()) in (\n  select user_id from team_user where team_user.team_id = projects.team_id\n) )\n",[21,536,534],{"__ignoreMap":23},[10,538,539],{},"O guia do Supabase a reescreve para ler as equipes uma vez e comparar com essa\nlista:",[14,541,544],{"className":542,"code":543,"language":199,"meta":23},[197],"using ( team_id in (\n  select team_id from team_user where user_id = (select auth.uid())\n) )\n",[21,545,543],{"__ignoreMap":23},[10,547,548,549,551,552,554,555,557],{},"Depois rode de novo o ",[21,550,244],{}," de antes e compare ",[21,553,272],{}," e\n",[21,556,276],{}," com o que você tinha.",[162,559],{"alt":560,"caption":561,"src":562},"Duas prateleiras com as mesmas doze linhas. À esquerda, uma linha de busca passa por cada linha, cada uma tem um visto e três estão acesas. À direita, uma ficha de índice com três abas aponta direto para essas mesmas três linhas acesas, e as outras não têm marca.","Sem índice, a política lê cada linha para achar as poucas que são suas. Com um índice, o Postgres vai direto a elas.","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fevery-row-or-the-few-1600x700.png",[31,564,566],{"id":565},"devo-aumentar-o-statement-timeout","Devo aumentar o statement timeout?",[10,568,569],{},"Só para uma consulta que você mediu, reescreveu e ainda precisa, e aí para essa\nfunção, não para um papel inteiro.",[10,571,572,573,575],{},"Os limites são de propósito. O guia de importação de dados do Supabase diz que\neles existem para dividir os recursos de forma justa e impedir que consultas\nlongas afetem o sistema todo. O limite de ",[21,574,102],{}," é dividido por todos os\nvisitantes sem login, e qualquer um pode mandar esse pedido com a chave\npublicável que vai dentro do seu app. Subir de três para trinta segundos dá a\ncada um desses pedidos trinta segundos do seu banco.",[10,577,578,579,582],{},"Quando um trabalho realmente leva mais tempo, dê o limite à função que o\nexecuta. O guia do Supabase descreve isso para funções recorrentes que precisam\nde uma exceção no tempo de execução, e funciona para uma função que o seu app\nchama com ",[21,580,581],{},"supabase.rpc(…)",":",[14,584,587],{"className":585,"code":586,"language":199,"meta":23},[197],"alter function public.monthly_totals() set statement_timeout to '20s';\n",[21,588,586],{"__ignoreMap":23},[10,590,591,592,595,596,599],{},"Se mesmo assim você mudar um papel, os comandos do guia são\n",[21,593,594],{},"alter role authenticated set statement_timeout = '15s';"," e depois\n",[21,597,598],{},"notify pgrst, 'reload config';",", para a Data API pegar o valor novo. O\nSupabase limita a 60 segundos as consultas das suas bibliotecas cliente, seja\nqual for o valor que você definir.",[31,601,603],{"id":602},"duas-correções-que-calam-a-mensagem-e-abrem-a-tabela","Duas correções que calam a mensagem e abrem a tabela",[10,605,606],{},"Desligar o Row Level Security na tabela, e mandar o pedido com a chave secreta.\nAs duas deixam a consulta rápida porque as duas pulam a política, e as duas\nentregam as linhas a pessoas que nunca deviam tê-las.",[10,608,609,612,613,616,617,620,621,620,624,252,627,630,631,633],{},[182,610,611],{},"Desligar."," Sem política para rodar, nada é verificado por linha e o timeout\nsome. O Supabase imprime o próprio aviso ao lado do teste que sugere isso:\ndesligar o Row Level Security expõe cada linha da tabela a qualquer papel com a\npermissão correspondente. O guia dele também diz que, em projetos existentes,\numa tabela nova em ",[21,614,615],{},"public"," começa com ",[21,618,619],{},"select",", ",[21,622,623],{},"insert",[21,625,626],{},"update",[21,628,629],{},"delete","\nconcedidos a ",[21,632,102],{},", o papel de um visitante sem login. Sem a política, essas\npermissões são tudo o que fica entre esse visitante e a tabela.",[10,635,636,639,640,642,643,645,646,650,651,653,654,438],{},[182,637,638],{},"A chave secreta."," O guia do Supabase diz que o papel ",[21,641,128],{}," por trás\ndela também tem ",[21,644,156],{},", então nenhuma política roda. Essa chave fica num\nservidor, e uma enviada pelo navegador é uma chave que qualquer um consegue ler\nno seu site;\n",[230,647,649],{"href":648},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","quais chaves são seguras num frontend","\nexplica o par. Ela também não ganha muito tempo, porque o guia dá ao\n",[21,652,128],{}," os mesmos 8 segundos do ",[21,655,134],{},[10,657,658,659,663],{},"Se alguma tabela sua responde a um pedido sem login nenhum é uma das nove\nverificações da ",[230,660,662],{"href":661},"\u002Fsecurity-scanner","análise gratuita da Reeve",". Ela lê o seu\nsite no ar do jeito que um visitante vê, leva uns 20 segundos e não precisa de\nconta.",[31,665,667],{"id":666},"mantendo-a-política-rápida-e-a-tabela-fechada","Mantendo a política rápida e a tabela fechada",[10,669,670,673],{},[182,671,672],{},"Uma política que você consertou hoje vai ter uma próxima versão."," O seu\nbuilder escreve políticas sempre que um recurso precisa de uma, então a próxima\npode voltar a chamar uma função por linha, ou abrir a tabela para uma tela\ncarregar.",[10,675,676],{},[182,677,678,682],{},[230,679,681],{"href":680},"\u002Fwebsite-monitoring","Reeve Monitor"," verifica o seu app de fora, a cada hora:",[684,685,686,690,693,700],"ul",{},[687,688,689],"li",{},"as nove verificações a cada hora, inclusive se alguma tabela responde a um pedido sem login",[687,691,692],{},"se o app está no ar, a cada 60 segundos",[687,694,695,696,699],{},"uma mensagem quando um resultado ",[182,697,698],{},"muda",", para que uma tabela que começa a responder a desconhecidos não espere você olhar",[687,701,702],{},"um relatório mensal do que ele viu",[10,704,705],{},[182,706,707,711],{},[230,708,710],{"href":709},"\u002Fsupabase-backups","Reeve Care"," guarda uma cópia do seu banco Supabase de\nantes da sua mudança:",[684,713,714,717,720,723,726],{},[687,715,716],{},"uma cópia criptografada conforme uma agenda, guardada no armazenamento do próprio Reeve na UE, fora da sua conta Supabase",[687,718,719],{},"cada cópia verificada antes de contar, contando as linhas de cada tabela",[687,721,722],{},"uma restauração em um clique que salva o que está lá agora antes de substituir",[687,724,725],{},"também os seus arquivos enviados, assim que você conectar uma credencial de Storage",[687,727,728],{},"tudo o que o Monitor faz",[31,730,732],{"id":731},"o-que-fazer-hoje","O que fazer hoje",[734,735,736],"key-takeaways",{},[684,737,738,744,760,766,772],{},[687,739,740,741,743],{},"Procure ",[21,742,176],{}," nos logs do Postgres e anote a consulta e o papel que a enviou.",[687,745,746,747,749,750,752,753,755,756,252,758,438],{},"Meça essa consulta com ",[21,748,244],{}," como ",[21,751,102],{}," ou ",[21,754,115],{},", os papéis que o seu app usa, e leia ",[21,757,272],{},[21,759,276],{},[687,761,762,763,765],{},"Envolva em ",[21,764,412],{}," cada chamada de função nas políticas dessa tabela, inclusive os seus próprios helpers que o Performance Advisor não aponta.",[687,767,768,769,771],{},"Crie um índice na coluna que cada política compara, e acrescente ",[21,770,502],{}," a cada política feita só para usuários com login.",[687,773,774],{},"Aumente um limite por último, na única função que precisa, e deixe o Row Level Security ligado.",[10,776,777,778,781],{},"Comece pela tabela por trás da página que falhou. Se ela ainda não tem\npolíticas próprias,\n",[230,779,780],{"href":457},"ligar o Row Level Security em cada tabela","\ntem as três formas de que a maioria das tabelas precisa.",{"title":23,"searchDepth":783,"depth":783,"links":784},3,[785,787,788,789,790,791,792,793,794,795],{"id":33,"depth":786,"text":34},2,{"id":62,"depth":786,"text":63},{"id":169,"depth":786,"text":170},{"id":237,"depth":786,"text":238},{"id":290,"depth":786,"text":291},{"id":426,"depth":786,"text":427},{"id":565,"depth":786,"text":566},{"id":602,"depth":786,"text":603},{"id":666,"depth":786,"text":667},{"id":731,"depth":786,"text":732},"Noções de segurança","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcover-1200x630.png","Um cronômetro com o ponteiro além da marca, na frente de uma prateleira longa de linhas em que só as primeiras têm um visto.","Supabase \"canceling statement due to statement timeout\": uma consulta passou do limite do seu papel, 3 segundos para um visitante. Veja antes a política RLS.",false,"md",[803,805,808,811,814],{"q":34,"a":804},"O Postgres parou a sua consulta porque ela durou mais do que o papel que a enviou permite, e desfez o que ela tinha feito. O Supabase dá 3 segundos a um visitante sem login e 8 a um usuário com login. O erro traz o código 57014, que o Postgres também usa para uma consulta cancelada a pedido, então leia a frase além do número.",{"q":806,"a":807},"Por que a minha consulta funciona no SQL Editor mas dá timeout no meu app?","Porque o SQL Editor trabalha com o papel postgres e o seu app não. O Supabase não dá ao postgres um limite próprio, e o papel tem bypassrls, então o editor nunca executa as suas políticas de Row Level Security. O seu app roda como anon ou authenticated, com limite de 3 ou 8 segundos e cada política verificada em cada linha que a consulta lê.",{"q":809,"a":810},"Row Level Security pode causar um statement timeout?","Pode. O Postgres verifica a política em cada linha que a consulta lê, e uma chamada de função dentro da política roda de novo para cada uma. Em medições que o Supabase publicou para uma tabela de 100.000 linhas, uma política que chamava um helper is_admin() levou 11.000 milissegundos, e a mesma política com a chamada envolvida como (select is_admin()) levou 7.",{"q":812,"a":813},"Como aumento o statement timeout no Supabase?","Para um trabalho lento específico, defina-o na função que o executa com alter function … set statement_timeout. Para um papel inteiro, rode alter role com o novo statement_timeout e depois notify pgrst, 'reload config' para a Data API pegar o valor. O Supabase limita a 60 segundos as consultas das suas bibliotecas cliente. Conserte a política antes, porque o limite de anon é dividido por todos os visitantes sem login.",{"q":815,"a":816},"Devo desligar o RLS para a consulta ficar mais rápida?","Não. A consulta fica mais rápida porque nenhuma política roda, e a tabela passa a ficar aberta a qualquer papel com permissão sobre ela. O guia do Supabase diz que, em projetos existentes, uma tabela nova em public começa com select, insert, update e delete concedidos a anon, o papel de um visitante sem login. Envolva as chamadas de função e crie um índice.","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",[819,820,821,822,823,824,825],"canceling statement due to statement timeout supabase","canceling statement due to statement timeout","supabase statement timeout","57014 supabase","supabase timeout consulta anon","supabase rls lento","supabase aumentar statement timeout",{},true,"Supabase \"canceling statement due to statement timeout\"","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","2026-10-31",{"title":5,"description":799},"blog\u002Fcanceling-statement-due-to-statement-timeout",[834,835,836],"\"canceling statement due to statement timeout\" no Supabase significa que o Postgres parou uma consulta porque ela durou mais do que o papel que a enviou permite: 3 segundos para um visitante sem login, 8 para um com login. Nada do que a consulta estava fazendo é mantido.","A mesma consulta funciona no SQL Editor porque o editor trabalha com o papel postgres, que não tem limite próprio e pula por completo as suas políticas de Row Level Security. O seu app aplica cada política a cada linha que lê.","Conserte a política antes de mexer no limite: envolva as chamadas de função em (select …), crie um índice na coluna que a política compara e nomeie o papel. Um limite maior para visitantes dá a qualquer desconhecido mais tempo com o seu banco.","BJId4vrVQfqP2_k5geTI213ykwJXelp1KpMyVwL9EAs",[839,845,851,857,863,869,875,881,887,893,894,901,907,913,919,925,931,937,943,949,955,961,967,973,979,985,991,997,1003,1009,1015,1021,1027,1032,1038,1044,1050,1056,1062,1068,1073,1079,1085,1091,1097,1103,1108,1114,1120,1126,1132,1138,1144,1150,1156,1162,1168,1174,1180,1186,1192,1198,1203,1209,1215,1221,1227,1233,1239,1245,1251,1257,1263,1269,1275,1281,1287,1293,1299,1305,1311,1317,1323,1329,1334,1340,1346,1352,1357,1363],{"path":840,"title":841,"description":842,"published":843,"category":796,"image":844,"draft":800},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\", explicado","Supabase \"max client connections reached\": o pooler não tem lugar para mais um cliente. A porta da sua string de conexão define o limite.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":846,"title":847,"description":848,"published":849,"category":796,"image":850,"draft":800},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Erro do Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": o Google está desativado no seu projeto Supabase. Como ativar e corrigir o redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":852,"title":853,"description":854,"published":855,"category":796,"image":856,"draft":800},"\u002Fblog\u002Fviolates-foreign-key-constraint","Erro do Supabase \"violates foreign key constraint\" ao inserir","Supabase \"insert or update on table violates foreign key constraint\": sua linha aponta para uma linha que não existe. Qual, por quê, e como corrigir.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":858,"title":859,"description":860,"published":861,"category":796,"image":862,"draft":800},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Erro do Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": uma coluna obrigatória chegou vazia. De onde veio o null, e como corrigir.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":864,"title":865,"description":866,"published":867,"category":796,"image":868,"draft":800},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": para onde foi a sessão","\"Auth session missing!\" é o supabase-js sem achar nenhuma sessão logada e sem chegar a perguntar ao Supabase. Para onde foi a sessão, e a correção.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":870,"title":871,"description":872,"published":873,"category":796,"image":874,"draft":800},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ninguém está logado","\"invalid claim: missing sub claim\": o Supabase Auth recebeu um token autêntico sem nenhum usuário, a chave do projeto no lugar de uma sessão.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":876,"title":877,"description":878,"published":879,"category":796,"image":880,"draft":800},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": a causa real","\"Failed to send a request to the Edge Function\": o navegador não recebeu uma resposta legível. O console dele diz por quê e se a sua função rodou.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":882,"title":883,"description":884,"published":885,"category":796,"image":886,"draft":800},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Por que o Supabase redireciona links de e-mail para localhost:3000","Se o Supabase redireciona para localhost:3000, a Site URL nunca foi trocada ou o seu endereço falta em Redirect URLs. A solução, e o curinga a evitar.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":888,"title":889,"description":890,"published":891,"category":796,"image":892,"draft":800},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" num link novo","Num link enviado há um minuto, \"Email link is invalid or has expired\" no Supabase costuma significar que um filtro de e-mail o usou antes. Como resolver.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":829,"title":5,"description":799,"published":830,"category":796,"image":817,"draft":800},{"path":895,"title":896,"description":897,"published":898,"category":899,"image":900,"draft":800},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" no Supabase, e o que vai junto","\"Database error deleting user\" no Supabase: seu banco recusou a exclusão. O motivo está nos seus logs, e a correção decide o que mais é apagado.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":902,"title":903,"description":904,"published":905,"category":796,"image":906,"draft":800},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" no Supabase","O webhook do Stripe numa Edge Function do Supabase diz \"No signatures found matching the expected signature\"? São duas causas. Continue verificando.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":908,"title":909,"description":910,"published":911,"category":796,"image":912,"draft":800},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" no Supabase: as três causas","O Supabase diz \"Invalid login credentials\" para senha errada, e-mail desconhecido e conta Google. Como saber qual é, e por que é vago.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":914,"title":915,"description":916,"published":917,"category":796,"image":918,"draft":800},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": o erro real","\"Edge Function returned a non-2xx status code\" quer dizer que sua função do Supabase respondeu com um erro. Veja onde ler o erro real.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":920,"title":921,"description":922,"published":923,"category":796,"image":924,"draft":800},"\u002Fblog\u002Fcertificate-not-trusted","Certificado não confiável: três causas além do vencimento","Certificado não confiável mesmo com a data certa? Ele cita outro endereço, assinou a si mesmo ou falta um elo na cadeia. Veja como saber qual.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":926,"title":927,"description":928,"published":929,"category":796,"image":930,"draft":800},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": leia as aspas","Supabase \"invalid input syntax for type uuid\": seu app enviou algo que não é um id. Leia as aspas, segure a consulta, mantenha a coluna.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":932,"title":933,"description":934,"published":935,"category":796,"image":936,"draft":800},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\", explicado","Supabase \"duplicate key value violates unique constraint\": o valor já está em uso. Ache a coluna, escolha uma correção e tire o valor da tela.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":938,"title":939,"description":940,"published":941,"category":796,"image":942,"draft":800},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\" e a tabela está lá","Supabase \"relation does not exist\" ou PGRST205: nenhuma tabela tem esse nome nesse schema. Quatro verificações, e o que expor um schema abre.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":944,"title":945,"description":946,"published":947,"category":796,"image":948,"draft":800},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" mostra os nomes de argumentos que seu app enviou. Compare-os com a função.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":950,"title":951,"description":952,"published":953,"category":796,"image":954,"draft":800},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" costuma ser um nome que não bate. Quatro verificações e a linha que recarrega.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":956,"title":957,"description":958,"published":959,"category":796,"image":960,"draft":800},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": dois limites, um só código","Supabase \"Email Rate Limit Exceeded\" limita cada email que seu projeto envia: 2 por hora no remetente embutido. O que conta e como aumentar.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":962,"title":963,"description":964,"published":965,"category":796,"image":966,"draft":800},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 causas","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" desconecta seus usuários. Três causas, e como o log do Auth separa cada uma.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":968,"title":969,"description":970,"published":971,"category":796,"image":972,"draft":800},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": três causas","Supabase \"permission denied for schema public\" é um grant que falta no schema. O que o removeu, e a linha que o devolve.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":974,"title":975,"description":976,"published":977,"category":796,"image":978,"draft":800},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": as três coisas que isso significa","Supabase \"Bucket not found\" é uma de três coisas: um link público para um bucket privado, um nome que não bate exatamente ou o projeto errado.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":980,"title":981,"description":982,"published":983,"category":796,"image":984,"draft":800},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: qual chave parou de funcionar?","Um erro Supabase invalid JWT é o PGRST301: um token assinado não passou na verificação. Num projeto novo isso é a sessão, não a chave de API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":986,"title":987,"description":988,"published":989,"category":796,"image":990,"draft":800},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" quase sempre é nenhuma","O Supabase devolve PGRST116, \"JSON object requested, multiple (or no) rows returned\", quando a consulta não achou nada. Linha escondida parece ausente.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":992,"title":993,"description":994,"published":995,"category":796,"image":996,"draft":800},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" no Supabase: onde olhar","\"Database error saving new user\" quer dizer que algo preso ao seu cadastro no Supabase falhou e tudo foi desfeito. O erro real está nos seus logs.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":998,"title":999,"description":1000,"published":1001,"category":796,"image":1002,"draft":800},"\u002Fblog\u002Fwhat-is-supabase","O que é Supabase? O banco de dados que seu builder escolheu","O que é Supabase: o banco de dados, o login e o armazenamento de arquivos do seu app. O Supabase cuida dos servidores; as regras das suas linhas são suas.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":1004,"title":1005,"description":1006,"published":1007,"category":796,"image":1008,"draft":800},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Uma chave AWS exposta no seu frontend não é como uma chave OpenAI","Uma chave de acesso da AWS exposta no seu frontend lê e grava no seu armazenamento. A solução costuma ser uma presigned URL, não uma chave nova.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1010,"title":1011,"description":1012,"published":1013,"category":796,"image":1014,"draft":800},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" ao enviar","\"New row violates row-level security policy for table objects\" quer dizer que o seu envio não tem regra insert. Deixar o bucket público não cria nenhuma.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":1016,"title":1017,"description":1018,"published":1019,"category":796,"image":1020,"draft":800},"\u002Fblog\u002Fbase44-security-scan","Scan de segurança do Base44: o que só ele enxerga","O scan de segurança do Base44 verifica sete tipos de problema por dentro. Esta é a metade que ele lê e mais ninguém, e a metade que ele nunca olha.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":1022,"title":1023,"description":1024,"published":1025,"category":796,"image":1026,"draft":800},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Sua chave de API vazou. A ordem em que agir","Uma chave de API vazou e você não sabe o que fazer primeiro. Nem toda chave no seu frontend é um vazamento, e a ordem importa mais que a pressa.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":462,"title":1028,"description":1029,"published":1030,"category":796,"image":1031,"draft":800},"\"Infinite recursion detected in policy\" sem desligar o RLS","\"Infinite recursion detected in policy for relation\" significa que a sua policy perguntou à tabela que ela protege. Veja como quebrar o círculo.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":1033,"title":1034,"description":1035,"published":1036,"category":796,"image":1037,"draft":800},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" no Supabase, e a correção errada","\"No API key found in request\" significa que sua requisição chegou ao Supabase sem chave. Quase toda resposta aponta para as regras do seu banco.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":1039,"title":1040,"description":1041,"published":1042,"category":796,"image":1043,"draft":800},"\u002Fblog\u002Fis-base44-safe","O Base44 é seguro? O que vimos em 5.442 apps Base44","O Base44 é seguro? Rodamos nove verificações em 5.442 apps Base44 no ar. Quase todas tiraram B por motivos que o dono nunca escolheu.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":1045,"title":1046,"description":1047,"published":1048,"category":796,"image":1049,"draft":800},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Esconder uma chave de API: mova para uma Edge Function do Supabase","Esconder uma chave de API é tirá-la do navegador, e uma Edge Function do Supabase é o menor lugar para guardá-la. Dois passos em volta pesam mais.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":1051,"title":1052,"description":1053,"published":1054,"category":796,"image":1055,"draft":800},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Seu arquivo .env está exposto? Os doze caminhos para testar","Seu arquivo .env está exposto no seu próprio servidor web? Doze endereços dizem isso em um minuto, e um acerto significa que tudo nele já é público.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":1057,"title":1058,"description":1059,"published":1060,"category":796,"image":1061,"draft":800},"\u002Fblog\u002Fis-v0-safe","Segurança do v0: os 1.790 aplicativos v0 escaneados tiraram A","A segurança do v0 medida em 1.790 aplicativos v0 no ar: todos tiraram A. Só 17 citavam um banco de dados, e é sobretudo isso que esse A mede.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":1063,"title":1064,"description":1065,"published":1066,"category":796,"image":1067,"draft":800},"\u002Fblog\u002Fis-bolt-safe","O Bolt é seguro? O que vimos em 1.123 aplicativos Bolt","O Bolt é seguro? Passamos 1.123 aplicativos Bolt no ar por nove verificações. A hospedagem saiu limpa. Os achados: chaves e tabelas abertas nos aplicativos.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":232,"title":1069,"description":1070,"published":1071,"category":796,"image":1072,"draft":800},"O Supabase caiu ou o problema é o seu app? Como saber","O Supabase caiu ou o problema é o seu app? Um projeto pausado, um banco cheio e um erro seu parecem iguais. Quatro verificações separam os casos.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":1074,"title":1075,"description":1076,"published":1077,"category":796,"image":1078,"draft":800},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","O Supabase criptografa meus dados? Sim. Veja o que isso impede","O Supabase criptografa os dados? Sim: AES-256 em repouso, TLS em trânsito, SOC 2 e ISO 27001. O que cada um cobre, e o vazamento que nenhum deles impede.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":1080,"title":1081,"description":1082,"published":1083,"category":796,"image":1084,"draft":800},"\u002Fblog\u002Fsupabase-free-plan-limits","O Supabase é gratuito? Sim, com estes limites e sem backups","Sim: o plano gratuito do Supabase vai até 500 MB de banco e 5 GB de egress, sem nenhum backup. O que para em cada limite e o que muda no Pro de $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":1086,"title":1087,"description":1088,"published":1089,"category":899,"image":1090,"draft":800},"\u002Fblog\u002Ftest-your-supabase-backup","Teste o backup do seu Supabase antes do dia em que precisar","Como testar o backup do seu Supabase: restaurar num projeto de teste, contar as linhas, entrar e procurar a linha que falta num arquivo cortado.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":1092,"title":1093,"description":1094,"published":1095,"category":899,"image":1096,"draft":800},"\u002Fblog\u002Fsupabase-backup-github-action","Backup grátis do Supabase com uma GitHub Action, e a pegadinha","Um backup do Supabase com GitHub Action é grátis e serve para muitos apps. O workflow, a connection string certa e o egress de cada execução.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":1098,"title":1099,"description":1100,"published":1101,"category":899,"image":1102,"draft":800},"\u002Fblog\u002Fdownload-your-supabase-backup","Por que você não consegue baixar seu backup do Supabase","Você não consegue baixar seu backup do Supabase num projeto atual, porque a cópia diária é um snapshot físico. Como conferir e como ter uma cópia só sua.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":1104,"title":1105,"description":1106,"published":1101,"category":796,"image":1107,"draft":800},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": o grant que falta","A partir de 30 de outubro, uma tabela nova no Supabase responde \"permission denied for table\" até receber um grant. O e-mail mostra só metade.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1109,"title":1110,"description":1111,"published":1112,"category":796,"image":1113,"draft":800},"\u002Fblog\u002Fopen-api-endpoint-exposed","Um endpoint de API aberto é um problema? Leia o JSON","Seu scan apontou um endpoint de API aberto. Se isso importa depende do que voltou, e a maioria dos que encontramos era da própria plataforma.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1115,"title":1116,"description":1117,"published":1118,"category":796,"image":1119,"draft":800},"\u002Fblog\u002Flovable-security-scan","Escaneamento de segurança do Lovable: o que ele não prova","Escaneamento de segurança do Lovable: o que o Quick scan e o Deep scan checam, quando cada um roda, e a única coisa que nenhum escaneamento por dentro prova.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1121,"title":1122,"description":1123,"published":1124,"category":899,"image":1125,"draft":800},"\u002Fblog\u002Fsupabase-backup-auth-users","Por que seu dump do Supabase não tem usuários dentro","Rode supabase db dump sozinho e você recebe a forma do seu banco e nenhuma das linhas dele, sem o schema auth onde seus usuários moram.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1127,"title":1128,"description":1129,"published":1130,"category":796,"image":1131,"draft":800},"\u002Fblog\u002Fdomain-and-certificate-expiry","Domínio expirado, site fora do ar: o que acontece agora","Seu domínio expirou e seu site está fora do ar. O relógio que começa a correr, por que o certificado é o problema menor, e como conferir os dois.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1133,"title":1134,"description":1135,"published":1136,"category":796,"image":1137,"draft":800},"\u002Fblog\u002Fis-lovable-safe","O Lovable é seguro? O que vimos em 18.554 aplicativos Lovable","O Lovable é seguro? Passamos 18.554 aplicativos Lovable no ar por nove verificações. A plataforma foi a mais limpa de cinco. Os achados estavam nos aplicativos.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1139,"title":1140,"description":1141,"published":1142,"category":796,"image":1143,"draft":800},"\u002Fblog\u002Fvibe-coded-app-security-checklist","O checklist de segurança do vibe coding, em nove verificações","Um checklist de segurança do vibe coding com nove itens, cada um verificável no seu app de fora por qualquer pessoa, e cada um com um teste de uma linha.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1145,"title":1146,"description":1147,"published":1148,"category":796,"image":1149,"draft":800},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Uma chave secreta da Stripe no frontend pode mover dinheiro","Uma chave secreta da Stripe exposta no seu frontend pode reembolsar, cobrar e ler cada ficha de cliente que você tem. Sua chave pk_live_ é que deve estar aí.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1151,"title":1152,"description":1153,"published":1154,"category":796,"image":1155,"draft":800},"\u002Fblog\u002Fvite-and-next-public-env-vars","Variáveis de ambiente do Vite expostas: o prefixo diz publique isto","Variáveis de ambiente do Vite expostas no seu app: fizeram o que o prefixo pediu. VITE_ e NEXT_PUBLIC_ significam publique isto, e a IA nunca soube o custo.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1157,"title":1158,"description":1159,"published":1160,"category":796,"image":1161,"draft":800},"\u002Fblog\u002Fbase44-source-maps","Segurança no Base44: o que um scan aponta e o que é seu para corrigir","Segurança no Base44 em 5.438 apps escaneados: três achados em quase todos são da plataforma, o source map é o selo do Base44, e a sua parte é uma lista curta.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1163,"title":1164,"description":1165,"published":1166,"category":796,"image":1167,"draft":800},"\u002Fblog\u002Fis-cursor-ai-safe","O Cursor AI é seguro? O editor, o código e o app que você publicou","O Cursor AI é seguro? Três perguntas em uma busca: o que o Cursor guarda, o que o código que ele escreve erra, e se o app que você publicou está aberto.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1169,"title":1170,"description":1171,"published":1172,"category":796,"image":1173,"draft":800},"\u002Fblog\u002Fis-replit-safe","O Replit é seguro? O que vimos em 3.042 aplicativos Replit no ar","O Replit é seguro? Passamos 3.042 aplicativos Replit no ar por nove verificações externas. Os achados estavam no aplicativo publicado, não no host.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1175,"title":1176,"description":1177,"published":1178,"category":899,"image":1179,"draft":800},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: sua cópia do banco não tem nenhum arquivo","Um Supabase storage backup é uma tarefa à parte. Os backups do banco guardam a lista dos seus arquivos e nenhum deles, então cada upload fica quebrado.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1181,"title":1182,"description":1183,"published":1184,"category":899,"image":1185,"draft":800},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery do Supabase: preço e limites","O point-in-time recovery do Supabase rebobina seu banco para qualquer segundo da última semana. Custa $100 por mês além do Pro e cobre só o banco.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1187,"title":1188,"description":1189,"published":1190,"category":899,"image":1191,"draft":800},"\u002Fblog\u002Fsupabase-project-paused-recover","Projeto Supabase pausado? Seus dados continuam lá","O Supabase pausou seu projeto depois de uma semana sem atividade. Nada foi apagado, Restaurar fica ao lado do nome e você tem um ano antes disso mudar.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1193,"title":1194,"description":1195,"published":1196,"category":796,"image":1197,"draft":800},"\u002Fblog\u002Fsafest-ai-app-builder","Qual builder de apps com IA é mais seguro? 30.998 apps testados","Qual builder de apps com IA é mais seguro? Escaneamos 30.998 apps no ar do Lovable, Base44, Replit, v0 e Bolt. O builder não é o que decide sua nota.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":457,"title":1199,"description":1200,"published":1201,"category":796,"image":1202,"draft":800},"Ative Row Level Security em toda tabela do Supabase e comprove","Ativar Row Level Security no Supabase sem política fecha a tabela por completo. Uma política sem a chave ligada não faz nada. Aqui está o SQL, e o teste.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1204,"title":1205,"description":1206,"published":1207,"category":796,"image":1208,"draft":800},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": o que o aviso não vê","O Supabase marca \"RLS disabled in public\" como erro. Ele não diz nada sobre a política de leitura que deixa a sua tabela igualmente aberta.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1210,"title":1211,"description":1212,"published":1213,"category":796,"image":1214,"draft":800},"\u002Fblog\u002Frotate-supabase-service-role-key","Como rotacionar uma chave service_role do Supabase vazada","O Supabase manda fechar o vazamento primeiro. Outros guias mandam rotacionar agora. O que vale depende de para onde a sua chave service_role vazou.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1216,"title":1217,"description":1218,"published":1219,"category":796,"image":1220,"draft":800},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Scanners de segurança para vibe coding comparados, o nosso incluído","O melhor scanner de segurança para vibe coding depende de três perguntas que nenhuma lista de recursos responde. Oito ferramentas comparadas, com preços.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1222,"title":1223,"description":1224,"published":1225,"category":796,"image":1226,"draft":800},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: faça você mesmo as cinco verificações","Um Supabase security checker lê o seu app publicado em vez das configurações do projeto. Aqui estão as cinco verificações e como fazer cada uma sozinho.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1228,"title":1229,"description":1230,"published":1231,"category":796,"image":1232,"draft":800},"\u002Fblog\u002Fvibe-coding-security-scanner","Scanner de segurança para vibe coding: o que ele não vê","Um scanner de segurança para vibe coding lê seu app no ar, de fora. O que isso cobre, as quatro coisas que ele não consegue ver e como ler o resultado.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1234,"title":1235,"description":1236,"published":1237,"category":796,"image":1238,"draft":800},"\u002Fblog\u002Fmissing-security-headers","Cabeçalhos de segurança faltando: quando isso importa","Cabeçalhos de segurança faltando é o achado que nosso scanner mais imprime. Contra o que eles protegem e quando são a linha menos urgente do relatório.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1240,"title":1241,"description":1242,"published":1243,"category":796,"image":1244,"draft":800},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Sua chave de API da OpenAI está exposta no frontend. Troque-a.","Uma chave de API da OpenAI exposta no frontend não pode ser presa a um domínio. Troque-a hoje, mova a chamada para o seu servidor e limite o gasto.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1246,"title":1247,"description":1248,"published":1249,"category":796,"image":1250,"draft":800},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Chave de API exposta no frontend: o que 30.998 apps entregam","Uma chave de API exposta no seu frontend costuma ser uma chave do Google Maps. Escaneamos 30.998 apps vibe-coded e contamos quais segredos vazam de verdade.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1252,"title":1253,"description":1254,"published":1255,"category":899,"image":1256,"draft":800},"\u002Fblog\u002Fsupabase-backup-tools-compared","Ferramentas de backup do Supabase comparadas, a nossa incluída","Quatro tipos de ferramenta de backup do Supabase, o que cada uma copia de verdade e quando uma GitHub Action gratuita ganha de pagar, nós inclusive.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1258,"title":1259,"description":1260,"published":1261,"category":796,"image":1262,"draft":800},"\u002Fblog\u002Freplit-secrets-explained","Como usar secrets no Replit, e o que ainda assim é publicado","Como usar secrets no Replit: adicionar um, ler de volta e resolver as duas causas do undefined. E as chaves que a ferramenta Secrets não consegue proteger.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1264,"title":1265,"description":1266,"published":1267,"category":899,"image":1268,"draft":800},"\u002Fblog\u002Fback-up-supabase-free-tier","Backups do plano gratuito do Supabase: como fazer sem terminal","No plano gratuito do Supabase não existe backup nenhum: a cópia é você que faz. Como fazer uma pelo painel e o que a rota do CSV deixa para trás.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1270,"title":1271,"description":1272,"published":1273,"category":796,"image":1274,"draft":800},"\u002Fblog\u002Fis-supabase-secure","O Supabase é seguro? É. Seu projeto é outra pergunta","O Supabase é seguro? A plataforma é auditada, criptografada e passa por pentests. A documentação deles diz onde isso termina e começam suas configurações.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1276,"title":1277,"description":1278,"published":1279,"category":796,"image":1280,"draft":800},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Onde ficam as chaves de API do Supabase: anon, service_role e URL","A URL do projeto, a chave anon e a chave service_role ficam todas numa página do painel. Aqui está onde ela fica, e qual dos quatro valores vai no seu app.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1282,"title":1283,"description":1284,"published":1285,"category":796,"image":1286,"draft":800},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy no Supabase. E agora?","\"New row violates row-level security policy\" significa que o Supabase recusou uma escrita. O conserto rápido reabre a tabela para qualquer um.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1288,"title":1289,"description":1290,"published":1291,"category":796,"image":1292,"draft":800},"\u002Fblog\u002Fcors-wildcard-security-risk","Um curinga CORS é um risco de segurança? Quase nunca.","Um curinga CORS é um risco de segurança? Em geral é o padrão do seu builder e não entrega nada que o seu servidor já não desse a qualquer um que pedisse.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1294,"title":1295,"description":1296,"published":1297,"category":899,"image":1298,"draft":800},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching do Supabase não é backup. Ele só anda para a frente.","Por que o branching do Supabase não é backup: um branch começa sem os seus dados e um merge só leva o esquema. Para que ele serve e o que usar no lugar.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1300,"title":1301,"description":1302,"published":1303,"category":899,"image":1304,"draft":800},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Como restaurar um backup do Supabase, e o que quebra depois","Como restaurar um backup do Supabase pelo painel ou por um arquivo de dump, o que a restauração substitui e por que o seu app pode continuar quebrado no fim.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1306,"title":1307,"description":1308,"published":1309,"category":796,"image":1310,"draft":800},"\u002Fblog\u002Fsupabase-storage-bucket-public","Seu bucket do Supabase Storage é público. Isso é um problema?","Um bucket público do Supabase Storage significa que quem tem a URL de um arquivo pode abri-lo. Não significa que alguém possa listar o que está lá dentro.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1312,"title":1313,"description":1314,"published":1315,"category":796,"image":1316,"draft":800},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Uma chave de API do Google no frontend é um problema?","Uma chave de API do Google exposta no seu frontend é a chave que nosso scanner mais encontra, e quase sempre está tudo bem. Um ajuste gratuito decide isso.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1318,"title":1319,"description":1320,"published":1321,"category":899,"image":1322,"draft":800},"\u002Fblog\u002Fai-agent-deleted-my-database","Um agente de IA apagou meus dados do Supabase. O que eu recupero?","Um agente de IA apagou dados do seu banco. O que você recupera já estava decidido antes de ele rodar, e os próximos minutos decidem o resto.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1324,"title":1325,"description":1326,"published":1327,"category":796,"image":1328,"draft":800},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Qualquer um consegue ler seu banco Supabase? Testamos 3.680 apps","Qualquer um consegue ler seu banco de dados Supabase sem fazer login? Escaneamos 30.998 apps no ar criadas com builders de IA e medimos quantas dizem que sim.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1330,"title":1331,"description":1332,"published":1327,"category":796,"image":1333,"draft":800},"\u002Fblog\u002Fsource-maps-exposed-in-production","Source maps expostos: seu app está publicando o código original","Um source map exposto deixa qualquer um ler o código original do seu app, comentários incluídos. A verificação de 30 segundos e o que importa de verdade.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1335,"title":1336,"description":1337,"published":1338,"category":796,"image":1339,"draft":800},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: é a mesma coisa que a anon key?","O Supabase trocou anon e service_role por chaves publicáveis e secretas. Qual delas pertence ao seu app e qual nunca deve estar lá?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1341,"title":1342,"description":1343,"published":1344,"category":899,"image":1345,"draft":800},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","O Supabase faz backup do meu banco de dados? Depende do plano.","O Supabase faz backup do seu banco de dados? Todo dia nos planos pagos, e nada no gratuito. Como descobrir o que você tem e o que essa cópia não cobre.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1347,"title":1348,"description":1349,"published":1350,"category":796,"image":1351,"draft":800},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","O Supabase Row Level Security está ligado. A tabela continua pública.","Ligar o Supabase Row Level Security não protege uma tabela. Quem protege são as políticas, e a que consertou o seu app pode deixar qualquer um entrar.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1353,"title":1354,"description":1355,"published":1350,"category":899,"image":1356,"draft":800},"\u002Fblog\u002Fversion-history-is-not-a-backup","O histórico de versões não é backup. Ele não desfaz um delete.","Lovable e Bolt guardam um histórico de versões do seu código. Seu banco de dados é um serviço à parte, e voltar atrás não traz os seus dados de volta.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1358,"title":1359,"description":1360,"published":1361,"category":899,"image":1362,"draft":800},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Três formas de fazer backup de um banco Supabase, e o que falta","O painel, o pg_dump e um serviço gerenciado. O que cada um salva de verdade, o que deixa de fora sem avisar e qual sobrevive a perder a conta.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":648,"title":1364,"description":1365,"published":1361,"category":796,"image":1366,"draft":800},"Quais chaves de API são seguras no navegador e quais não são","Sua chave anon do Supabase foi feita para ser pública. Sua chave service_role não, e ela ignora todas as regras que você criar. Como diferenciar as duas.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213648889]