Pular para o conteúdo

Backups

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.

Vlad Tkachenko11 min de leitura
Um arquivo lacrado com três linhas de dados e, ao lado, um registro pautado de pessoas que ficou de fora e é cortado pela borda do quadro.

Em resumo

  • O Supabase publica o backup dele como três comandos. O que você provavelmente rodou é o segundo, e seus usuários estão no terceiro.
  • Rode supabase db dump sem outras flags e você recebe a forma das suas tabelas e nada do conteúdo delas, e o schema auth onde seus usuários moram fica de fora até disso.
  • Uma única busca no arquivo que você já tem diz qual de três coisas você está segurando.

Você fez a coisa responsável. Procurou como fazer backup de um banco Supabase, rodou o comando que encontrou e guardou o arquivo em um lugar seguro.

Aí um dia você precisa dele. Você despeja o arquivo em um projeto novo e a restauração termina sem um único erro. Cada tabela que você já criou está lá, e cada uma delas está vazia. Seus usuários estão pior ainda: a parte do banco onde eles moram, um schema chamado auth, nunca chegou ao arquivo.

Aqui está a parte que quase todo guia pula: supabase db dump sozinho não é uma cópia dos seus dados. Sem outras flags ele escreve a forma do seu banco e nada do conteúdo, e deixa auth de fora até disso. O Supabase publica o backup como três comandos, e suas contas viajam no terceiro.

Ajuda pensar em um hotel. Suas tabelas são os quartos e tudo que está dentro deles. O registro da recepção, aquele com o nome de cada hóspede, é do hotel. E uma planta te mostra cada quarto do prédio sem colocar um único hóspede lá dentro.

Um backup do Supabase inclui meus usuários?

Depende de qual comando escreveu o arquivo, e o comando que a maioria roda não inclui.

Seus usuários não são linhas de uma tabela sua. O Supabase guarda eles em uma gaveta separada do mesmo banco, o schema auth, junto com as senhas com hash, os provedores pelos quais entraram e as sessões que mantêm. Suas tabelas ficam em uma gaveta chamada public, e cada coluna user_id nelas é uma referência para dentro de auth.

Um schema é exatamente isso: uma gaveta com nome dentro de um banco. public é seu. auth é do Supabase, e storage também, que guarda a linha que descreve cada arquivo enviado. A documentação do próprio Supabase chama esses de schemas gerenciados e diz que normalmente não precisam ser puxados a menos que você os tenha modificado, que é por que as ferramentas tratam eles diferente das suas tabelas.

Essa divisão é o que permite a um comando produzir dois arquivos que se parecem e contêm coisas completamente diferentes.

Rodado sozinho, o comando de dump copia a forma da sua gaveta e para na fronteira das duas que o Supabase administra.

O que o comando de dump escreve sozinho

A planta. Nenhuma linha, e nada de auth.

A página de referência do Supabase para o comando diz isso em duas frases. Ele roda pg_dump com flags extras para excluir os schemas gerenciados pelo Supabase, e entre os ignorados estão auth, storage e os criados por extensões. A mesma página diz depois que o dump padrão não contém dados nem papéis próprios, e que você consegue esses pedindo com --data-only e --role-only.

Então isto, que é o que você provavelmente rodou:

supabase db dump --db-url "postgresql://…your connection string…" -f backup.sql

produz um arquivo cheio de instruções CREATE TABLE. Cada coluna, cada índice, cada policy que você escreveu nas suas tabelas, e nenhuma linha de nada.

A razão de isso ser pior que um arquivo obviamente vazio é que funciona. E ele também não parece pequeno: cada definição de tabela, cada índice e cada policy que você já escreveu estão ali, e para um app de verdade isso é muito texto. Um backup vazio se anuncia sozinho. Este restaura limpo, e a primeira coisa que te diz o contrário é uma tela de login que nenhuma conta consegue passar.

O mesmo comando escreve os dois. Qual deles você tem na mão depende de uma flag, e os dois restauram sem erro.

Como confiro o dump que eu já tenho?

Abra em um editor de texto e busque por auth. O que aparecer coloca seu arquivo em um de três grupos.

  1. Nenhuma ocorrência. O schema auth não está nesse arquivo de forma alguma. É isso que um supabase db dump puro escreve.
  2. Ocorrências, mas só em linhas que começam com CREATE, ALTER ou GRANT. Você tem o desenho do registro e ninguém dentro.
  3. Uma linha COPY "auth"."users" ou COPY auth.users, com linhas de dados embaixo até uma linha com \. Ou uma sequência de linhas começando com INSERT INTO "auth"."users". Suas contas estão aí.

Se você preferir fazer na linha de comando, dois greps respondem a mesma pergunta:

grep -c 'auth.*users' backup.sql
grep -n 'COPY .*auth.*users\|INSERT INTO .*auth.*users' backup.sql

O primeiro diz se o schema chegou no arquivo. O segundo diz se as pessoas chegaram. Um zero dos dois, em um arquivo com que você contava, é melhor descobrir hoje do que na manhã em que você precisa dele.

Busque por storage já que está aí, e leia com atenção o que encontrar. Essas linhas são a lista dos seus arquivos enviados, que é uma coisa diferente dos arquivos, e nenhum backup de banco em nenhum plano contém aqueles.

Como exporto os usuários auth do Supabase?

Com o comando de dados, que é um comando diferente do que escreve o schema.

O guia de backup e restauração do Supabase publica o backup como três arquivos, e vale ver os três juntos porque o formato disso é a resposta:

supabase db dump --db-url "postgresql://…" -f roles.sql --role-only
supabase db dump --db-url "postgresql://…" -f schema.sql
supabase db dump --db-url "postgresql://…" -f data.sql --use-copy --data-only \
  -x "storage.buckets_vectors" -x "storage.vector_indexes"

A segunda linha é a que é rodada sozinha. A terceira é a que tem seus usuários dentro.

Esses dois fatos parecem uma contradição e não são. A frase da página de referência do Supabase sobre excluir auth descreve o dump de schema, e o dump de dados percorre esse schema também.

Se você só quer as contas, nomeie o schema e recebe aquela gaveta sozinha:

supabase db dump --db-url "postgresql://…" -f users.sql --data-only --use-copy --schema auth

Antes de confiar em qualquer um desses, adicione --dry-run e leia o que volta. Ele imprime o comando pg_dump que a ferramenta vai rodar sem rodar, então você vê com os próprios olhos quais schemas entram e quais ficam de fora na versão que você instalou. Leia essa saída uma vez e você nunca mais precisa acreditar neste artigo, nem em nenhum outro, o que importa porque as flags realmente se mexem entre versões e o arquivo fica com a mesma cara dos dois jeitos.

Tem também o caminho direto, e é para isso que serve um pg_dump simples: nomeie as gavetas que você quer e ele leva.

pg_dump "postgresql://…" --schema public --schema auth --schema storage \
  --no-owner --file backup.sql

Uma coisa para notar sobre o arquivo de schema, porque explica por que isso tudo é separado. Um projeto Supabase novo chega com um schema auth já construído, na versão que o serviço de login roda hoje. Despejar por cima a versão do seu projeto antigo colocaria um desenho mais velho em cima de um que funciona. O que você quer levar é o conteúdo do registro, e é isso que o arquivo de dados tem.

O que quebra na hora de devolver os usuários

Duas coisas, e o Supabase documenta as duas.

Os triggers, que podem criptografar uma coluna duas vezes. O comando de restauração do guia do Supabase tem no meio uma instrução fácil de ler como enfeite:

psql \
  --single-transaction \
  --variable ON_ERROR_STOP=1 \
  --file roles.sql \
  --file schema.sql \
  --command 'SET session_replication_role = replica' \
  --file data.sql \
  --dbname "postgresql://…"

Essa linha do meio desliga os triggers pelo tempo da operação, e o guia diz que ela está ali para impedir que colunas sejam criptografadas uma segunda vez na entrada. Despeje um arquivo de dados sem ela e as senhas chegam já embaralhadas por um processo que já tinha sido aplicado nelas, e nada depois desfaz isso.

Propriedade e permissões, que param o despejo. Um dump tirado de um projeto Supabase carrega linhas que se referem a papéis que o projeto novo não deixa você tocar. As notas de solução de problemas do mesmo guia dizem para comentar qualquer linha com ALTER ... OWNER TO "supabase_admin" em schema.sql, e uma linha específica GRANT "postgres" TO "cli_login_postgres" em roles.sql. As duas são uma edição de texto antes de começar, e as duas param o despejo com a linha em que ele engasgou impressa na sua tela.

Meus usuários vão ter que entrar de novo?

As senhas deles passam. As sessões não, a menos que você leve mais uma coisa junto.

O Supabase diz que você pode migrar cada tabela do schema auth, usuários e suas senhas com hash incluídos, então ninguém precisa redefinir uma senha que já tinha. Nenhuma senha é legível em ponto nenhum disso; o que se move é o hash dela.

Uma sessão é outra coisa. Ela é provada por um token assinado com o segredo JWT do seu projeto, e cada projeto tem o seu. O Supabase diz que se o projeto novo assinar com outro segredo, cada token que já está no navegador de alguém fica inválido e é pedido àquela pessoa que entre de novo. Você pode evitar isso colocando o segredo do projeto antigo no novo, e o preço está escrito na mesma página: trocar o segredo JWT regenera as chaves anon e service_role daquele projeto, então seu app precisa receber as novas antes de conseguir falar com qualquer coisa. Qual chave é qual, e qual delas pode estar no seu app, é o que convém ter claro antes de colar qualquer uma.

Então a versão honesta é que uma restauração normalmente pede a todo mundo que entre uma vez. Isso é um e-mail para o suporte. Não é uma conta perdida, e a diferença entre as duas coisas é se o schema auth estava no seu arquivo.

Três coisas continuam de fora, faça o que fizer com as flags. Seus arquivos enviados, porque o Storage guarda os bytes fora do banco e nenhum dump em nenhum plano alcança eles. Suas edge functions, que são um download à parte e cujos import maps, observa o Supabase, não são buscados automaticamente. E as configurações do seu projeto, que são configuração e não dados e são redigitadas à mão.

O que fazer esta semana

O que fazer

  • Pegue o arquivo de backup mais recente que você tem e busque auth dentro dele. Grupo um, dois ou três da seção acima, e você sabe em um minuto.
  • Se for grupo um ou dois, tire hoje um dump de dados com --data-only e --use-copy, e guarde ao lado do arquivo de schema em vez de no lugar dele. Você precisa dos dois.
  • Adicione --dry-run ao comando que você escolher e leia a saída uma vez, para saber quais gavetas a sua versão da ferramenta leva.
  • Anote a ordem da restauração onde você vá encontrar: roles, depois schema, depois SET session_replication_role = replica, depois data.
  • Restaure uma vez em um projeto descartável e então tente entrar como um usuário de verdade. É a única conferência que testa aquilo de que este artigo trata.

Fazer isso uma vez na mão vale a pena de qualquer jeito que você acabe fazendo backup, porque enquanto você não abriu um dump só teve a palavra backup. Se você continua fazendo na mão é outra pergunta, e os três caminhos e quanto cada um custa é onde ela é respondida.

Onde o Reeve Care entra

O Care tira a cópia em um calendário, e o registro vai dentro.

A cópia guarda suas tabelas e suas contas. O botão de restaurar devolve suas tabelas e deixa as contas onde estão.
  • Suas contas estão na cópia. O schema auth viaja junto com suas tabelas, porque uma cópia de um app Supabase sem os usuários dele é uma cópia da metade. As linhas de storage que descrevem seus arquivos vêm também, e os próprios arquivos assim que você conecta uma credencial do Storage.
  • O botão de restaurar devolve suas tabelas e deixa as contas em paz. Despejar auth.users em cima de um projeto vivo desloga todo mundo e traz de volta contas que alguém apagou de propósito, então isso continua sendo um pedido com uma pessoa em cima. Assim apertar o botão no desespero não consegue deslogar os clientes que você estava tentando ajudar.
  • A cópia é relida antes de contar como tirada. A data no seu painel é a última vez que uma cópia foi aberta e verificada, nunca a hora em que um job começou ou um arquivo chegou.
  • Restaurar tira antes uma foto do estado atual, então a própria restauração tem um desfazer.

O Care começa em $49 por mês para um app. Esse é um preço de tabela, e a página de preços às vezes está abaixo do número daqui e nunca acima.

Como uma cópia é tirada, conferida e devolvida está desenhado passo a passo na página de backups do Supabase.

Antes de fechar esta aba, abra seu dump mais recente e busque auth nele. É o jeito mais rápido de descobrir se aquilo que você vinha chamando de backup devolveria seus clientes, e se a resposta for não, restaurar um do jeito certo é a próxima leitura.

Perguntas frequentes

Um backup do Supabase inclui meus usuários?

Depende de qual comando escreveu o arquivo. Seus usuários moram em um schema chamado auth, que pertence ao serviço de login. Um supabase db dump puro deixa auth de fora e não contém nenhuma linha de nada, porque o dump padrão é só o schema. A metade de dados do dump, que é um segundo comando com a flag --data-only, é a que carrega seus usuários. É exatamente por isso que o Supabase publica o backup como três comandos.

Por que auth.users está faltando no meu dump?

Porque você quase certamente rodou o dump de schema. O Supabase documenta que o comando exclui os schemas gerenciados por ele, que entre os ignorados estão auth e storage, e que o dump padrão não contém dado nenhum. Isso é proposital: um projeto novo chega com o próprio schema auth já construído pelo serviço de login, então despejar por cima uma cópia mais velha substituiria algo que funciona. O que você quer mover é o conteúdo, e quem carrega isso é o dump de dados.

Como exporto os usuários auth do Supabase?

Com o comando de dados, que é separado do comando de schema. Rode supabase db dump com --data-only e --use-copy para escrever um arquivo de dados, e as tabelas de auth vêm junto. Se você só quer as contas, adicione --schema auth e recebe um arquivo com aquele schema sozinho. Antes de confiar em qualquer um dos dois, adicione --dry-run: ele imprime o comando pg_dump que a CLI vai rodar sem rodar, então você lê quais schemas entram na versão que você tem.

As senhas sobrevivem a uma restauração do Supabase?

Sim, se o schema auth estava no arquivo. O Supabase diz que você pode migrar cada tabela do schema auth, senhas com hash incluídas, então ninguém precisa redefinir nem recriar. A única coisa que pode estragar isso é despejar os dados sem desligar os triggers antes, que é a razão de o Supabase colocar SET session_replication_role = replica no meio do próprio comando de restauração dele. Pule essa linha e uma coluna já criptografada é criptografada uma segunda vez na entrada.

Meus usuários vão continuar logados depois de uma restauração?

Não, se o projeto novo assinar com outro segredo. Uma sessão é provada por um token assinado com o segredo JWT do projeto, e o Supabase diz que um segredo novo invalida os tokens existentes, então é pedido a todo mundo que entre de novo. Você pode levar o segredo antigo junto e manter todos logados, mas o Supabase também diz que trocar o segredo JWT regenera as chaves anon e service_role daquele projeto, então seu app precisa das novas.

O que mais um dump do Supabase deixa de fora?

Seus arquivos enviados, antes de tudo. O Storage guarda uma linha no seu banco para cada arquivo e o arquivo em si em outro lugar, então nenhum dump de banco em nenhum plano contém os bytes. As edge functions são um download à parte, e o Supabase observa que os import maps e os arquivos deno.json não são buscados automaticamente. As configurações do projeto, os provedores de auth e os segredos são configuração e não dados e moram no dashboard, então são redigitados à mão em um projeto novo.

Escrito por

Vlad Tkachenko

Fundador da Reeve

Passo meus dias olhando apps criados com Lovable, Bolt, v0, Cursor e Replit, e a curta lista de erros que aparecem neles sem parar.

Mais sobre o autor

Leia depois

Todos os artigos

Não sabe como está o seu próprio app?

Faça um scan gratuito e receba uma nota clara de A a F em cerca de 20 segundos. Sem conta e sem cartão.

Verificar meu app grátis

Verificação externa automatizada, não uma auditoria completa. A ausência de achados não é garantia de segurança.