Vai al contenuto

Backups

Testa il tuo backup di Supabase prima del giorno in cui serve

Come testare il tuo backup di Supabase: ripristinarlo in un progetto di prova, contare le righe, accedere e cercare la riga che manca a un file troncato.

Vlad Tkachenko16 min di lettura
Una fila di file di backup sigillati e identici, il primo illuminato, accanto a un database vuoto tratteggiato che aspetta di riceverne uno.

In breve

  • Per testare un backup di Supabase, ripristinalo in un progetto che non conta, confronta i numeri di righe con il database in produzione e accedi come te stesso. Solo un ripristino distingue un file buono da uno rotto.
  • Abbiamo troncato un dump a metà di una tabella e l'abbiamo ricaricato con le opzioni che raccomanda Supabase. psql ha finito senza alcun errore, e le tabelle sono tornate incomplete.
  • Fai la prova una volta adesso, poi ogni tre mesi e dopo ogni cambiamento nel modo in cui viene fatto il backup, e annota la data ogni volta.

Da qualche parte c'è un file con dentro il tuo database. Una GitHub Action ne scrive uno ogni notte, oppure hai lanciato una volta i tre comandi di backup di Supabase, oppure il tuo piano fa copie giornaliere. Ha il nome giusto e più o meno la dimensione che ti aspetteresti. Nessuno l'ha mai aperto.

Ecco la parte che le guide di configurazione rimandano a dopo: un backup che non è mai stato ripristinato è una promessa, non una copia. L'unico modo per testare un backup di Supabase è ripristinarlo, apposta, in un posto dove non conta, e guardare cosa torna. Un dump troncato a metà, un dump senza nemmeno una riga e un dump del progetto sbagliato stanno tutti nello storage con esattamente l'aspetto di uno buono.

Pensa a una prova di evacuazione. Un edificio la fa in una mattina qualunque, quando non brucia niente, perché nessuno dovrebbe scendere quelle scale per la prima volta il giorno in cui si riempiono di fumo. Fuori, qualcuno fa l'appello sulla lista di chi era dentro, e qualcuno annota la data sul foglio vicino alla porta. Una prova di ripristino è la stessa cosa: fare il percorso, contare, annotare.

Come faccio a sapere se il mio backup di Supabase funziona davvero?

Ripristinalo e guarda. È l'unico test che esista, perché niente nel file in sé separa un backup buono da uno rotto.

La prova prende la tua copia più recente, la ricarica in un progetto che non conta e fa tre domande al risultato. C'è ogni tabella, con più o meno tante righe quante quella in produzione? La riga più recente è della notte in cui è stata fatta la copia? Riesci ad accedere come te stesso? Un file buono risponde sì a tutte e tre, e ogni modo in cui un backup va storto ne fallisce almeno una.

Cinque modi in cui un backup è sbagliato e sembra giusto lo stesso

Tutti e cinque finiscono nella notte senza errori, e tutti e cinque lasciano un file con il solito nome nel solito posto. Si distinguono solo quando il file viene ricaricato.

Cosa non va nel fileCome ci arriva, di solitoIl passo della prova che lo scopre
Si ferma a metàUno script che passa pg_dump a gzip riporta cosa ha fatto gzip. Un dump morto a metà viene salvato, e il job dice che è andato tutto bene. Un disco pieno o un caricamento che si è arreso fanno lo stessoLa riga finale, poi i conteggi
Ha le tue tabelle e nessuna delle righesupabase db dump è stato lanciato senza --data-only, e così scrive solo la strutturaI conteggi: ogni tabella a zero
Ha le righe e nessuno degli accountIl dump ha nominato solo il tuo schema, e i tuoi utenti vivono in uno chiamato authLa ricerca di auth.users, poi l'accesso
Sono i dati di un altro progettoLa connection string punta a una copia di staging o a un vecchio progettoLa riga più recente, del giorno sbagliato
Non si carica affattoUn dump di Postgres 17 ricaricato in Postgres 15, o righe di proprietario che il nuovo progetto rifiutaIl ripristino si ferma con un errore

Il secondo e il terzo sono l'argomento di perché il tuo dump di Supabase non ha utenti, ed entrambi nascono da un comando di dump lanciato con meno opzioni di quelle che servivano. Il primo ci ha sorpreso, quindi ha una sezione tutta sua.

Nello storage i sei file sembrano uguali. Ricaricato, solo il primo ti restituisce il database che avevi.

Un file di backup troncato fallisce al ripristino?

Non sempre. Ne abbiamo troncato uno a metà di una tabella, l'abbiamo ricaricato con le opzioni che usa la guida stessa di Supabase, e psql ha finito senza alcun errore.

Il test era piccolo e facile da ripetere. Il 27 settembre 2026 abbiamo fatto il dump di un database con due tabelle, una da 5.000 righe e una da 300, troncato il file in tre punti diversi e ricaricato ogni versione con psql di Postgres 17.11. Ogni caricamento ha usato --single-transaction e --variable ON_ERROR_STOP=1, le due opzioni che servono a fermare un ripristino al primo problema e annullare tutto.

  • Troncato a metà di un valore, psql si è fermato con un errore e non ha scritto niente. È il risultato che ti augureresti.
  • Troncato dentro l'ultima colonna di una riga, è finito con codice di uscita 0, che è il modo in cui un programma dice di aver avuto successo. La prima tabella è tornata con 2.596 delle sue 5.000 righe, all'ultima mancava metà del testo, e la seconda tabella è tornata vuota.
  • Troncato esattamente tra le due tabelle, è finito anche lui con 0. La prima tabella era completa e la seconda vuota.

Il motivo sta nel modo in cui un dump conserva le righe. Le righe di ogni tabella stanno in un blocco che finisce con una riga che contiene solo \., e quando il file finisce prima di quella riga, psql prende la fine del file per la fine del blocco. L'unico segno che doveva esserci dell'altro è una riga che sarebbe dovuta stare proprio alla fine.

Quella riga è la firma di pg_dump. Un dump completo contiene le parole PostgreSQL database dump complete verso la fine, e uno troncato no. Dei tre file che scrive la CLI di Supabase, la riga sopravvive solo in data.sql, perché la CLI toglie tutti i commenti dal file dello schema (verificato con la versione 2.111 della CLI). Quindi data.sql è il file in cui cercare, e quella ricerca è il secondo passo della prova.

Il caricamento ha riportato successo. La prima tabella è tornata piena a metà e la seconda vuota.

Dove dovrei ripristinarlo?

In un progetto Supabase che non conta: un progetto di prova nel tuo account, o un Supabase che gira sul tuo computer. Mai nel progetto che usa la tua app.

Un progetto di prova su Supabase è la cosa più simile al tuo progetto reale, ed è la destinazione per cui è scritta la guida di Supabase a backup e ripristino: il suo primo passo è creare un nuovo progetto. Con il piano gratuito hai diritto a due progetti gratuiti attivi, e quelli in pausa non contano, quindi un progetto di prova di solito non costa niente finché il tuo database sta nel piano gratuito. In un'organizzazione a pagamento, il calcolo di un nuovo progetto viene addebitato a ore, quindi eliminalo quando la prova è finita.

Supabase sul tuo computer non costa niente e non richiede un account. La CLI di Supabase fa girare tutto lo stack in locale con Docker: supabase init, poi supabase start, e mostra un indirizzo del database sulla porta 54322 e una publishable key per il progetto locale. Prima di avviarlo, apri supabase/config.toml e imposta major_version sulla versione principale di Postgres del tuo progetto. Il commento sopra quell'impostazione dice che devono coincidere, e la versione del tuo progetto è in Project Settings, poi General.

Su Postgres 15 c'è un tranello. A meno che il job di backup non abbia fissato una versione, la CLI ha fatto la copia con pg_dump 17, e il file dei dati contiene allora, vicino all'inizio, SET transaction_timeout = 0, un'impostazione che Postgres 15 non riconosce, quindi il caricamento si ferma su quella riga. Per la prova, imposta major_version su 17. Poi applica al job di backup la correzione di una riga descritta nell'articolo sulla GitHub Action, perché il progetto in cui ripristineresti davvero è ancora su 15.

Un Postgres nudo in Docker, senza niente di Supabase dentro, non basta. Un dump di Supabase fa riferimento a cose che crea solo Supabase, come lo schema auth in cui vivono i tuoi utenti e il ruolo authenticated nominato dalle tue regole di sicurezza, e il ripristino si ferma alla prima riga che ne menziona una.

Una cautela, perché il progetto di prova ora contiene una copia reale. Ci sono dentro gli indirizzi email dei tuoi utenti, quindi non collegarci né la tua app né i suoi webhook, ed eliminalo quando hai finito.

I job pianificati sono la parte che non arriva. Se il tuo progetto li esegue con l'estensione pg_cron, i tre file della CLI riportano l'estensione e nessuno dei suoi job, perché i job sono righe di cron.job e il dump dei dati lascia fuori quelle righe. L'abbiamo verificato il 4 ottobre 2026 con la versione 2.119 della CLI, ripristinando un database che aveva un job pianificato. Il progetto di prova resta quindi tranquillo, e anche un ripristino vero da questi file parte senza alcun job pianificato, quindi tieni le tue chiamate a cron.schedule in un posto da cui puoi rieseguirle.

Come testare un backup di Supabase, passo per passo

Sei passi, e i primi tre avvengono prima di ripristinare qualsiasi cosa.

  1. Trova la copia più recente e leggi la sua data. Se è più vecchia dell'ultima esecuzione programmata, il job si è fermato, ed è la tua prima scoperta.
  2. Cerca dump complete in data.sql. Un risultato significa che il file è arrivato alla fine. Nessuno significa che è stato troncato, qualunque sia la sua dimensione. La ricerca di un editor di testo funziona quanto un terminale:
    grep -c 'dump complete' data.sql
    
  3. Cercaci dentro i tuoi utenti. Una riga che inizia con COPY "auth"."users" con delle righe sotto significa che i tuoi account sono nel file:
    grep -n 'COPY .*auth.*users' data.sql
    
  4. Ricaricalo nel progetto di prova con il comando della guida di Supabase, puntato sulla connection string del progetto di prova. Su un Supabase locale quella stringa è postgresql://postgres:postgres@127.0.0.1:54322/postgres.
    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://…the spare's connection string…"
    
  5. Conta le righe e leggi la più recente, in entrambi i database. La query è nella prossima sezione.
  6. Accedi al progetto di prova come te stesso. Il comando è nella sezione successiva.

Se il passo 4 si ferma con un errore, la prova ha già fatto il suo lavoro. Le note di risoluzione dei problemi in fondo alla guida di Supabase coprono i due errori più comuni, entrambi sui ruoli, e come ripristinare un backup di Supabase spiega da cosa ti protegge ogni opzione di quel comando.

Mancano in quelle note altri due arresti in roles.sql. Li abbiamo incontrati entrambi il 4 ottobre 2026, ricaricando i file di due database Postgres 17, uno dei quali un progetto Supabase, in una copia locale nuova di Supabase: "supabase_admin" is a reserved role, only superusers can modify it, su una riga che inizia con ALTER ROLE "supabase_admin", e permission denied for parameter log_min_messages, su una riga che inizia con GRANT SET ON PARAMETER. Entrambe le righe configurano ruoli che Supabase crea da sé in ogni progetto, quindi metti -- all'inizio di ciascuna per trasformarla in un commento e riesegui il comando. La nostra Action di backup le commenta già quando fa la copia.

Cosa contare, e rispetto a cosa

Conta ogni tabella nel progetto di prova e nel tuo progetto in produzione con la stessa query, e metti le due liste una accanto all'altra. La copia dovrebbe essere una notte indietro rispetto al database in produzione: un po' più bassa su una tabella che cresce, e mai a zero su una tabella che aveva righe.

È l'appello sulla lista di chi era dentro. Incolla la query nell'editor SQL di ogni progetto e premi Run. Conta le righe di ogni tabella del tuo schema e di auth:

select table_schema, table_name,
       (xpath('/row/n/text()',
         query_to_xml(format('select count(*) as n from %I.%I', table_schema, table_name),
                      false, true, '')))[1]::text::bigint as row_count
  from information_schema.tables
 where table_schema in ('public', 'auth')
   and table_type = 'BASE TABLE'
 order by table_schema, table_name;

Legge ogni riga di ogni tabella, quindi su un database grande lanciala fuori dalle tue ore più affollate.

Poi leggi la riga più recente di una tabella che conosci, solo nel progetto di prova. Va bene qualsiasi tabella con una colonna created_at; metti il suo nome al posto di orders:

select max(created_at) from public.orders;

La risposta dovrebbe essere vicina all'ora in cui è girato il backup. Una data più vecchia di settimane, o righe che non riconosci, significano che il file viene da un altro progetto.

ControlloDoveCosa mostra una copia buona
Le righe di ogni tabellaEntrambiLe stesse tabelle, ognuna un po' indietro rispetto alla produzione, nessuna vuota che avesse righe
La riga più recenteProgetto di provaUn'ora della notte in cui è stata fatta la copia
Il tuo accountProgetto di provaLa tua email in auth.users
Un accessoProgetto di provaTorna un token

Perché l'accesso è il test che dimostra i tuoi account

Un conteggio di auth.users dimostra che le righe sono arrivate. Un accesso dimostra che funzionano: che la password salvata, il servizio di accesso del progetto di prova e il tuo indirizzo email vanno ancora d'accordo.

Usa il tuo account, con una password che conosci. L'indirizzo del progetto e la publishable key del progetto di prova sono nel suo pannello Connect, o nell'output di supabase start su un Supabase locale:

curl -X POST 'https://…the spare's project ref….supabase.co/auth/v1/token?grant_type=password' \
  -H "apikey: sb_publishable_…" \
  -H "Content-Type: application/json" \
  -d '{"email": "you@example.com", "password": "…"}'

È la chiamata di accesso della documentazione di Supabase stessa, diretta al progetto di prova. Una risposta che contiene access_token significa che il tuo account è arrivato con una password che funziona. Invalid login credentials, per un account che accede senza problemi alla tua app in produzione, significa che non è arrivato, e perché un dump arriva senza gli account è l'articolo per quel risultato.

Se tutti accedono alla tua app con Google, questa chiamata non ha niente da testare, perché nel progetto di prova non c'è un accesso con Google configurato. Cerca invece la tua email in auth.users dopo il ripristino. Questo mostra che la riga dell'account è arrivata, anche se non che la sua password funziona.

I file: la metà che un ripristino del database non può testare

La copia del database contiene una riga per ogni file caricato e nessuno dei file. Se copi i tuoi bucket di Storage con un job a parte, che è l'unico modo in cui vengono copiati, fai fare la prova anche a quella copia.

Prendi le tre righe più recenti dal database ripristinato:

select bucket_id, name from storage.objects order by created_at desc limit 3;

Trova quei tre percorsi nella tua copia dei file e aprili uno per uno. Un percorso senza un file dietro è un'immagine che i tuoi utenti vedrebbero rotta dopo un vero ripristino.

Posso testare i backup che Supabase fa per me?

Con un piano a pagamento sì, con Restore to a New Project. È l'unico modo per aprire una delle copie giornaliere di Supabase, perché sui progetti attuali non puoi scaricarle.

Supabase descrive la funzione come un modo per fare test in sicurezza. Scegli una copia nella scheda Restore to a New Project della pagina Backups, e Supabase ne costruisce un nuovo progetto con i tuoi utenti e le loro password hashate, pronto per gli stessi conteggi e lo stesso accesso. Due cose da sapere prima di premere. Il nuovo progetto viene fatturato come un progetto a sé, e Supabase ti mostra il costo prima di partire. E copia tutto, job pianificati compresi: Supabase dice che i job di pg_cron, pg_net e dei wrapper partono appena il ripristino è completato, senza modo di metterli in pausa prima. Se un job della tua app manda email o addebita una carta, lo farà anche il progetto di test.

Se tieni anche un file fuori dall'account, quel file ha bisogno di una prova tutta sua.

Ogni quanto dovrei testare un ripristino?

Una volta adesso, poi ogni tre mesi, e di nuovo ogni volta che cambia qualcosa nel modo in cui viene fatto il backup.

I cambiamenti che contano sono quelli che rompono un backup in silenzio: un workflow nuovo o modificato, una password del database reimpostata, il passaggio a un nuovo piano o a una nuova versione di Postgres, una nuova tabella in cui la tua app ha cominciato a scrivere. Dopo ognuno di questi, la prova del trimestre scorso non descrive più il file di questo trimestre.

Poi annotalo: è il foglio vicino alla porta. Una riga per prova, in un posto che raggiungi senza ciò che si è rotto: la data, quale file, i conteggi che contavano, se l'accesso ha funzionato e quanto è durata tutta la prova. Basta un file di testo nel repository del backup, e va bene anche un evento ricorrente nel calendario con i risultati incollati dentro. La data risponde a «quando l'abbiamo dimostrato l'ultima volta» nell'ora in cui qualcuno ha bisogno di saperlo, e la durata è la tua prima stima di quanto un vero ripristino terrebbe ferma la tua app.

Dove si inserisce Reeve Care

Care conserva copie del tuo database Supabase fuori dal tuo account Supabase, secondo l'orario del tuo piano, controlla ogni copia mentre viene fatta e la rimette al suo posto con un pulsante.

  • Le copie seguono l'orario del tuo piano, da una volta al giorno fino a ogni sei ore.
  • Una copia troncata viene scoperta mentre viene fatta. La riga finale di pg_dump deve essere nel file, altrimenti la copia non supera il controllo e non diventa mai la data nella tua dashboard.
  • Ogni tabella viene contata mentre la copia viene scritta. Quando una tabella che aveva righe nella copia precedente non ne ha nessuna in questa, una persona di Reeve lo viene a sapere.
  • I tuoi account ci sono, e anche i tuoi file caricati arrivano non appena colleghi una credenziale di Storage.
  • Ripristinare è un pulsante, e prima di sostituire qualsiasi cosa viene fatta una copia dello stato attuale.
  • Ogni copia si scarica come zip con schema.sql, data.sql, roles.sql e un manifest con il numero di righe di ogni tabella, che è la metà «rispetto a cosa» di questo articolo, già scritta.

Una prova trimestrale dimostra la copia che hai scelto quel giorno, e il controllo gira su ogni copia mentre viene fatta. La copia, il controllo e il ripristino sono disegnati passo per passo nella pagina sui backup di Supabase, e cosa include ogni piano, orario compreso, è nella pagina dei prezzi.

Cosa fare questa settimana

Cosa fare

  • Trova il tuo backup più recente e leggi la sua data. Se è più vecchio dell'ultima esecuzione programmata, sistema il job prima di tutto.
  • Cerca dump complete e COPY "auth"."users" in data.sql. Due ricerche ti dicono se il file arriva alla fine e se i tuoi account ci sono.
  • Crea un progetto di prova, o avvia Supabase sul tuo computer, e ricarica il file con il comando psql della guida di Supabase.
  • Lancia la query di conteggio su entrambi i database e metti le due liste una accanto all'altra. Leggi la riga più recente di una tabella che conosci.
  • Accedi al progetto di prova come te stesso.
  • Annota la data, i conteggi e quanto è durata, poi elimina il progetto di prova.

Prima di chiudere questa scheda, cerca dump complete nel tuo data.sql più recente. È una sola ricerca, e ti dice se il file che chiami backup arriva alla sua ultima riga. Se non hai ancora un file in cui cercare, una GitHub Action gratuita è il modo più rapido per cominciare a produrne.

FAQ

Come faccio a sapere se il mio backup di Supabase funziona davvero?

Ripristinalo in un progetto che non conta e guarda cosa torna. Confronta il numero di righe di ogni tabella con il database in produzione, controlla che la riga più recente sia della notte in cui è stata fatta la copia e accedi come te stesso. Niente nel file in sé distingue un dump buono da uno rotto: nome, dimensione e la spunta verde accanto al job sono uguali in entrambi i casi.

Ogni quanto dovrei testare un ripristino?

Una volta adesso, poi ogni tre mesi, e di nuovo ogni volta che cambia il modo in cui viene fatto il backup: un workflow nuovo o modificato, una password del database reimpostata, un nuovo piano o una nuova versione di Postgres, o una nuova tabella in cui scrive la tua app. Annota la data ogni volta, con i conteggi e quanto è durata, così la domanda su quando è stato dimostrato l'ultima volta ha una risposta.

Posso testare un ripristino senza toccare il database in produzione?

Sì, ed è sempre così che dovresti farlo. Ripristina in un progetto di prova su Supabase, cosa che il piano gratuito consente, o in un Supabase che gira sul tuo computer con la CLI e Docker. L'unica cosa che la prova fa al database in produzione è leggerlo una volta per contarne le righe. Elimina il progetto di prova alla fine, perché contiene una copia reale dei tuoi utenti.

Cosa dovrei controllare dopo aver ripristinato un backup?

Quattro cose. Il numero di righe di ogni tabella accanto a quello in produzione, dove la copia dovrebbe essere un po' indietro e mai a zero per una tabella che aveva righe. La riga più recente di una tabella che conosci, che dovrebbe essere della notte della copia. La tua email in auth.users. E un accesso come te stesso, l'unico controllo che dimostra che gli account funzionano e non solo che sono arrivati.

Il ripristino ha funzionato, ma nessuno riesce ad accedere. Perché?

Quasi sempre perché il file non ha mai contenuto i tuoi account. Supabase li tiene in uno schema chiamato auth, e un dump che ha nominato solo il tuo schema, o un supabase db dump senza opzioni, li lascia fuori mentre ogni tua tabella si ripristina senza problemi. Cerca prima COPY "auth"."users" nel file. Se manca, fai un dump dei dati con --data-only, che attraversa lo schema auth e porta con sé i tuoi utenti.

Un file di backup troncato fallisce al ripristino?

Non sempre. Abbiamo troncato un file di pg_dump in tre punti e ricaricato ogni versione con --single-transaction e ON_ERROR_STOP, le opzioni della guida al ripristino di Supabase. Un taglio a metà di un valore si è fermato con un errore. Un taglio dentro l'ultima colonna di una riga e un taglio tra due tabelle sono finiti entrambi senza errori, con le tabelle incomplete. Un dump completo contiene la riga PostgreSQL database dump complete verso la fine, quindi cercala prima di fidarti di un file.

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.