Vai al contenuto

Backups

Perché nel tuo dump Supabase non ci sono utenti

Lancia supabase db dump da solo e ottieni la forma del tuo database e nessuna delle sue righe, senza lo schema auth in cui vivono i tuoi utenti.

Vlad Tkachenko11 min di lettura
Un file sigillato con tre righe di dati, e accanto un registro rigato di persone rimasto fuori e tagliato dal bordo della cornice.

In breve

  • Supabase pubblica il suo backup come tre comandi. Quello che hai probabilmente lanciato è il secondo, e i tuoi utenti stanno nel terzo.
  • Lancia supabase db dump senza altri flag e ottieni la forma delle tue tabelle e niente del loro contenuto, e lo schema auth in cui vivono i tuoi utenti resta fuori perfino da quello.
  • Una sola ricerca nel file che hai già ti dice quale di tre cose stai tenendo in mano.

Hai fatto la cosa giusta. Hai cercato come fare il backup di un database Supabase, hai lanciato il comando che hai trovato e hai messo il file in un posto sicuro.

Poi un giorno ti serve. Rigiochi il file in un progetto nuovo e il ripristino finisce senza un solo errore. Ogni tabella che hai mai creato è lì, e ognuna di esse è vuota. I tuoi utenti stanno anche peggio: la parte del database in cui vivono, uno schema chiamato auth, non ha mai raggiunto il file.

Ecco la parte che quasi ogni guida salta: supabase db dump da solo non è una copia dei tuoi dati. Senza altri flag scrive la forma del tuo database e niente del suo contenuto, e auth lo lascia fuori perfino da quello. Supabase pubblica il backup come tre comandi, e i tuoi account viaggiano nel terzo.

Aiuta pensare a un albergo. Le tue tabelle sono le stanze e tutto quello che ci sta dentro. Il registro alla reception, quello con il nome di ogni ospite, è dell'albergo. E una pianta ti mostra ogni stanza dell'edificio senza metterci dentro un solo ospite.

Un backup di Supabase contiene i miei utenti?

Dipende da quale comando ha scritto il file, e il comando che lanciano quasi tutti non li contiene.

I tuoi utenti non sono righe di una delle tue tabelle. Supabase li tiene in un cassetto a parte dello stesso database, lo schema auth, insieme alle loro password hashate, ai provider con cui hanno fatto accesso e alle sessioni che hanno aperte. Le tue tabelle stanno in un cassetto chiamato public, e ogni colonna user_id che c'è dentro è un riferimento verso auth.

Uno schema è esattamente questo: un cassetto con un nome dentro un database. public è tuo. auth è di Supabase, e lo è anche storage, che tiene la riga che descrive ogni file caricato. La documentazione di Supabase chiama questi i suoi schemi gestiti e dice che di norma non serve scaricarli a meno che tu non li abbia modificati, ed è il motivo per cui gli strumenti li trattano diversamente dalle tue tabelle.

Questa divisione è ciò che permette a un comando di produrre due file che si somigliano e contengono cose del tutto diverse.

Lanciato da solo, il comando di dump copia la forma del tuo cassetto e si ferma al confine dei due che gestisce Supabase.

Cosa scrive il comando di dump da solo

La pianta. Nessuna riga, e niente da auth.

La pagina di riferimento di Supabase per il comando lo dice in due frasi. Lancia pg_dump con flag aggiuntivi per escludere gli schemi gestiti da Supabase, e tra quelli ignorati ci sono auth, storage e quelli creati dalle estensioni. La stessa pagina dice poi che il dump predefinito non contiene dati né ruoli personalizzati, e che li ottieni chiedendoli con --data-only e --role-only.

Quindi questo, che è quello che hai probabilmente lanciato:

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

produce un file pieno di istruzioni CREATE TABLE. Ogni colonna, ogni indice, ogni policy che hai scritto sulle tue tabelle, e nemmeno una riga di niente.

Il motivo per cui questo è peggio di un file palesemente vuoto è che funziona. Non sembra nemmeno piccolo: ogni definizione di tabella, ogni indice e ogni policy che hai mai scritto stanno lì dentro, e per una app vera è un sacco di testo. Un backup vuoto si annuncia da solo. Questo si ripristina pulito, e la prima cosa che ti dice il contrario è una pagina di accesso che nessun account riesce a superare.

Lo stesso comando scrive entrambi. Quale dei due hai in mano dipende da un flag, ed entrambi si ripristinano senza un errore.

Come controllo il dump che ho già?

Aprilo in un editor di testo e cerca auth. Quello che salta fuori mette il tuo file in uno di tre gruppi.

  1. Nessuna corrispondenza. Lo schema auth non è in questo file in nessuna forma. È quello che scrive un supabase db dump nudo.
  2. Corrispondenze, ma solo in righe che iniziano con CREATE, ALTER o GRANT. Hai il disegno del registro e nessuno dentro.
  3. Una riga COPY "auth"."users" oppure COPY auth.users, con righe di dati sotto fino a una riga che contiene \. Oppure una sequenza di righe che iniziano con INSERT INTO "auth"."users". I tuoi account ci sono.

Se preferisci farlo da riga di comando, due grep rispondono alla stessa domanda:

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

Il primo dice se lo schema ha raggiunto il file. Il secondo dice se ci sono arrivate le persone. Uno zero da entrambi, su un file su cui contavi, è meglio scoprirlo oggi che la mattina in cui ti serve.

Cerca anche storage già che ci sei, e leggi con attenzione quello che trovi. Quelle righe sono la lista dei tuoi file caricati, che è una cosa diversa dai file, e nessun backup di database su nessun piano contiene quelli.

Come esporto gli utenti auth di Supabase?

Con il comando dei dati, che è un comando diverso da quello che scrive lo schema.

La guida a backup e ripristino di Supabase pubblica il backup come tre file, e vale la pena vederli insieme perché la forma è la risposta:

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"

La seconda riga è quella che viene lanciata da sola. La terza è quella con dentro i tuoi utenti.

Questi due fatti sembrano una contraddizione e non lo sono. La frase sulla pagina di riferimento di Supabase riguardo all'esclusione di auth descrive il dump dello schema, e il dump dei dati percorre anche quello schema.

Se vuoi solo gli account, nomina lo schema e ottieni quel cassetto da solo:

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

Prima di fidarti di uno qualsiasi di questi, aggiungi --dry-run e leggi quello che torna. Stampa il comando pg_dump che lo strumento sta per lanciare senza lanciarlo, così vedi con i tuoi occhi quali schemi sono inclusi e quali esclusi sulla versione che hai installato. Leggi quell'output una volta e non dovrai più credere a questo articolo, né a nessun altro, il che conta perché i flag si spostano davvero tra le release e il file ha lo stesso aspetto in entrambi i casi.

C'è anche la via diretta, ed è a questo che serve un pg_dump semplice: nomina i cassetti che vuoi e se li prende.

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

Una cosa da notare sul file di schema, perché spiega perché tutto questo è diviso. Un progetto Supabase nuovo arriva con uno schema auth già costruito, nella versione che il servizio di accesso fa girare oggi. Rigiocarci sopra la versione del tuo vecchio progetto metterebbe un disegno più vecchio sopra uno che funziona. Quello che vuoi portare dall'altra parte è il contenuto del registro, ed è quello che tiene il file di dati.

Cosa si rompe quando rimetti dentro gli utenti

Due cose, e Supabase le documenta entrambe.

I trigger, che possono cifrare una colonna due volte. Il comando di ripristino della guida di Supabase ha in mezzo un'istruzione facile da leggere come riempitivo:

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://…"

Quella riga in mezzo spegne i trigger per tutta la durata, e la guida dice che sta lì per impedire che le colonne vengano cifrate una seconda volta mentre entrano. Rigioca un file di dati senza di lei e le password arrivano già mescolate da un processo che era già stato applicato, e niente dopo lo disfa.

Proprietà e permessi, che fermano il rigioco. Un dump preso da un progetto Supabase porta righe che si riferiscono a ruoli che il progetto nuovo non ti lascia toccare. Le note di risoluzione dei problemi della stessa guida dicono di commentare qualsiasi riga che contenga ALTER ... OWNER TO "supabase_admin" in schema.sql, e una riga precisa GRANT "postgres" TO "cli_login_postgres" in roles.sql. Entrambe sono una modifica di testo prima di partire, ed entrambe fermano il rigioco con la riga su cui si è inceppato stampata sullo schermo.

I miei utenti devono rifare il login?

Le loro password passano. Le loro sessioni no, a meno che tu non porti con loro una cosa in più.

Supabase dice che puoi migrare ogni tabella dello schema auth, utenti e loro password hashate compresi, quindi nessuno deve reimpostare una password che aveva già. Nessuna password è leggibile in nessun momento di tutto questo; quello che si sposta è il suo hash.

Una sessione è un'altra cosa. È provata da un token firmato con il segreto JWT del tuo progetto, e ogni progetto ha il suo. Supabase dice che se il progetto nuovo firma con un altro segreto, ogni token già presente nel browser di qualcuno diventa invalido e a quella persona viene chiesto di accedere di nuovo. Puoi evitarlo mettendo il segreto del vecchio progetto su quello nuovo, e sulla stessa pagina c'è scritto il prezzo: cambiare il segreto JWT rigenera le chiavi anon e service_role di quel progetto, quindi alla tua app vanno date quelle nuove prima che possa parlare con qualcosa. Quale chiave è quale, e quale di loro può stare nella tua app, è la cosa su cui essere sicuro prima di incollarne una.

Quindi la versione onesta è che un ripristino di solito chiede a tutti di accedere una volta. Quella è una mail al supporto. Non è un account perso, e la differenza tra le due cose è se lo schema auth era nel tuo file.

Tre cose continuano a non esserci, qualunque cosa tu faccia con i flag. I tuoi file caricati, perché Storage tiene i byte fuori dal database e nessun dump su nessun piano li raggiunge. Le tue edge function, che sono un download a parte e le cui import map, nota Supabase, non vengono prese automaticamente. E le impostazioni del tuo progetto, che sono configurazione e non dati e si riscrivono a mano.

Cosa fare questa settimana

Cosa fare

  • Prendi il file di backup più recente che hai e cercaci dentro auth. Gruppo uno, due o tre della sezione qui sopra, e lo saprai in un minuto.
  • Se è gruppo uno o due, prendi oggi un dump dei dati con --data-only e --use-copy, e tienilo accanto al file di schema invece che al suo posto. Ti servono entrambi.
  • Aggiungi --dry-run al comando su cui ti fermi e leggi l'output una volta, così sai quali cassetti prende la tua versione dello strumento.
  • Scriviti l'ordine del ripristino dove lo ritrovi: roles, poi schema, poi SET session_replication_role = replica, poi data.
  • Ripristina una volta in un progetto usa e getta, e poi prova ad accedere come un utente vero. È l'unico controllo che verifica la cosa di cui parla questo articolo.

Farlo una volta a mano vale la pena comunque tu finisca per fare i backup, perché finché non hai aperto un dump hai avuto solo la parola backup. Se continuare a mano è un'altra domanda, e le tre vie e quanto costa ciascuna è il posto in cui si risponde.

Dove si colloca Reeve Care

Care prende la copia secondo un calendario, e il registro è dentro.

La copia tiene le tue tabelle e i tuoi account. Il pulsante di ripristino rimette le tue tabelle e lascia gli account dove sono.
  • I tuoi account sono nella copia. Lo schema auth viaggia con le tue tabelle, perché una copia di una app Supabase senza i suoi utenti è una copia della metà. Le righe storage che descrivono i tuoi file vengono anche loro, e i file stessi appena colleghi una credenziale Storage.
  • Il pulsante di ripristino rimette le tue tabelle e lascia stare gli account. Rigiocare auth.users su un progetto vivo scollega tutti e riporta indietro account che qualcuno aveva cancellato apposta, quindi quella resta una richiesta con una persona sopra. Così premere il pulsante nel panico non può scollegare i clienti che stavi cercando di aiutare.
  • La copia viene riletta prima di contare come presa. La data sulla tua dashboard è l'ultima volta che una copia è stata aperta e verificata, mai il momento in cui un lavoro è partito o un file è atterrato.
  • Il ripristino prende prima un'istantanea dello stato attuale, così il ripristino stesso ha un annulla.

Care parte da €49 al mese per una app. È un prezzo di listino, e la pagina dei prezzi a volte sta sotto la cifra qui e mai sopra.

Come una copia viene presa, controllata e rimessa è disegnato passo per passo sulla pagina dei backup Supabase.

Prima di chiudere questa scheda, apri il tuo dump più recente e cercaci dentro auth. È il modo più veloce per scoprire se quello che stavi chiamando backup ti restituirebbe i tuoi clienti, e se la risposta è no, ripristinarne uno come si deve è la prossima cosa da leggere.

FAQ

Un backup di Supabase contiene i miei utenti?

Dipende da quale comando ha scritto il file. I tuoi utenti vivono in uno schema chiamato auth, che appartiene al servizio di accesso. Un supabase db dump nudo lascia fuori auth e non contiene nessuna riga di niente, perché il dump predefinito è solo lo schema. La metà dati del dump, un secondo comando con il flag --data-only, è quella che porta i tuoi utenti. Supabase pubblica il backup come tre comandi esattamente per questo.

Perché auth.users manca dal mio dump?

Perché quasi sicuramente hai lanciato il dump dello schema. Supabase documenta che il comando esclude i suoi schemi gestiti, che tra quelli ignorati ci sono auth e storage, e che il dump predefinito non contiene dati del tutto. È voluto: un progetto nuovo arriva con il proprio schema auth già costruito dal servizio di accesso, quindi rigiocarci sopra una copia più vecchia sostituirebbe qualcosa che funziona. Quello che vuoi spostare è il contenuto, e lo porta il dump dei dati.

Come esporto gli utenti auth di Supabase?

Con il comando dei dati, che è separato dal comando dello schema. Lancia supabase db dump con --data-only e --use-copy per scrivere un file di dati, e le tabelle di auth vengono con lui. Se vuoi solo gli account, aggiungi --schema auth e ottieni un file che contiene quello schema soltanto. Prima di fidarti di uno dei due, aggiungi --dry-run: stampa il comando pg_dump che la CLI sta per lanciare senza lanciarlo, così leggi quali schemi sono inclusi nella versione che hai.

Le password sopravvivono a un ripristino Supabase?

Sì, se lo schema auth era nel file. Supabase dice che puoi migrare ogni tabella dello schema auth, password hashate comprese, così nessuno deve reimpostarle o ricrearle. L'unica cosa che può rovinarle è rigiocare i dati senza prima disattivare i trigger, ed è per questo che Supabase mette SET session_replication_role = replica in mezzo al suo stesso comando di ripristino. Salta quella riga e una colonna già cifrata viene cifrata una seconda volta mentre entra.

I miei utenti resteranno collegati dopo un ripristino?

No, se il progetto nuovo firma con un altro segreto. Una sessione è provata da un token firmato con il segreto JWT del progetto, e Supabase dice che un segreto nuovo rende invalidi i token esistenti, quindi a tutti viene chiesto di accedere di nuovo. Puoi portarti dietro il vecchio segreto e tenerli collegati, ma Supabase dice anche che cambiare il segreto JWT rigenera le chiavi anon e service_role di quel progetto, quindi la tua app ha bisogno di quelle nuove.

Cos'altro lascia fuori un dump di Supabase?

I tuoi file caricati, prima di tutto. Storage tiene una riga nel tuo database per ogni file e il file stesso da un'altra parte, quindi nessun dump di database su nessun piano contiene i byte. Le edge function sono un download a parte, e Supabase nota che le import map e i file deno.json non vengono presi automaticamente. Le impostazioni del progetto, i provider auth e i segreti sono configurazione e non dati e vivono nella dashboard, quindi si riscrivono a mano in un progetto nuovo.

Scritto da

Vlad Tkachenko

Fondatore di Reeve

Passo le giornate a guardare app costruite con Lovable, Bolt, v0, Cursor e Replit, e la breve lista di errori che vi ricompaiono di continuo.

Altro sull'autore

Da leggere dopo

Tutti gli articoli

Non sai come sta messa la tua app?

Esegui una scansione gratuita e ottieni un voto chiaro da A a F in una ventina di secondi. Senza account e senza carta.

Scansiona la tua app gratis

Controllo esterno automatizzato, non un audit completo. L'assenza di risultati non è una garanzia di sicurezza.