Zum Inhalt springen

Backups

Warum in deinem Supabase-Dump keine Nutzer stehen

Führe supabase db dump allein aus und du bekommst die Form deiner Datenbank und keine einzige Zeile, und das auth-Schema mit deinen Nutzern fehlt ganz.

Vlad Tkachenko10 Min. Lesezeit
Eine versiegelte Archivdatei mit drei Datenzeilen, daneben ein liniertes Personenregister, das draußen steht und angeschnitten wird.

Kurz gesagt

  • Supabase veröffentlicht sein Backup als drei Befehle. Den, den du vermutlich ausgeführt hast, ist der zweite, und deine Nutzer stecken im dritten.
  • Führe supabase db dump ohne weitere Flags aus und du bekommst die Form deiner Tabellen und nichts von ihrem Inhalt, und das auth-Schema mit deinen Nutzern fehlt sogar darin.
  • Eine einzige Suche in der Datei, die du schon hast, sagt dir, welches von drei Dingen du in der Hand hältst.

Du hast das Vernünftige getan. Du hast nachgeschlagen, wie man eine Supabase-Datenbank sichert, den gefundenen Befehl ausgeführt und die Datei an einen sicheren Ort gelegt.

Dann brauchst du sie eines Tages. Du spielst die Datei in ein frisches Projekt ein, und die Wiederherstellung läuft ohne einen einzigen Fehler durch. Jede Tabelle, die du je angelegt hast, ist da, und jede einzelne davon ist leer. Deine Nutzer sind noch schlechter dran: Der Teil der Datenbank, in dem sie leben, ein Schema namens auth, hat die Datei nie erreicht.

Hier ist der Teil, den fast jede Anleitung überspringt: supabase db dump allein ist keine Kopie deiner Daten. Ohne weitere Flags schreibt es die Form deiner Datenbank und nichts von ihrem Inhalt, und auth lässt es sogar dabei weg. Supabase veröffentlicht das Backup als drei Befehle, und deine Konten fahren im dritten mit.

Es hilft, an ein Hotel zu denken. Deine Tabellen sind die Zimmer und alles darin. Das Gästebuch an der Rezeption, das mit jedem Namen darin, gehört dem Hotel. Und ein Grundriss zeigt dir jedes Zimmer im Haus, ohne einen einzigen Gast hineinzustellen.

Enthält ein Supabase-Backup meine Nutzer?

Das hängt davon ab, welcher Befehl die Datei geschrieben hat, und der Befehl, den die meisten ausführen, tut es nicht.

Deine Nutzer sind keine Zeilen in einer deiner eigenen Tabellen. Supabase hält sie in einer eigenen Schublade derselben Datenbank, dem auth-Schema, zusammen mit ihren gehashten Passwörtern, den Anbietern, über die sie sich angemeldet haben, und den Sitzungen, die sie halten. Deine eigenen Tabellen sitzen in einer Schublade namens public, und jede user_id-Spalte darin ist ein Verweis hinüber nach auth.

Ein Schema ist genau das: eine benannte Schublade in einer Datenbank. public gehört dir. auth gehört Supabase, und storage auch, in dem die Zeile liegt, die jede hochgeladene Datei beschreibt. Supabases eigene Dokumentation nennt diese seine verwalteten Schemas und sagt, dass sie normalerweise nicht gezogen werden müssen, solange du sie nicht verändert hast, weshalb das Werkzeug sie anders behandelt als deine Tabellen.

Diese Teilung ist es, die einen Befehl zwei Dateien schreiben lässt, die einander gleichen und völlig Verschiedenes enthalten.

Allein ausgeführt kopiert der Dump-Befehl die Form deiner eigenen Schublade und hält an der Grenze zu den beiden, die Supabase betreibt.

Was der Dump-Befehl allein schreibt

Den Grundriss. Keine Zeilen, und nichts aus auth.

Supabases Referenzseite zu dem Befehl sagt es in zwei Sätzen. Er führt pg_dump mit zusätzlichen Flags aus, um die von Supabase verwalteten Schemas auszuschließen, und zu den ignorierten gehören auth, storage und die von Erweiterungen angelegten. Dieselbe Seite sagt dann, dass der Standard-Dump keine Daten und keine eigenen Rollen enthält und dass du sie bekommst, indem du mit --data-only und --role-only danach fragst.

Das hier also, das du vermutlich ausgeführt hast:

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

erzeugt eine Datei voller CREATE TABLE-Anweisungen. Jede Spalte, jeder Index, jede Policy, die du auf deinen eigenen Tabellen geschrieben hast, und keine einzige Zeile von irgendetwas.

Der Grund, warum das schlimmer ist als eine offensichtlich leere Datei, ist, dass sie funktioniert. Klein ist sie auch nicht erkennbar: Jede Tabellendefinition, jeder Index und jede Policy, die du je geschrieben hast, steht darin, und das ist bei einer echten App eine Menge Text. Ein leeres Backup meldet sich von selbst. Dieses spielt sauber ein, und das Erste, was dir etwas anderes sagt, ist eine Anmeldeseite, an der kein Konto vorbeikommt.

Derselbe Befehl schreibt beide. Welche du in der Hand hältst, entscheidet ein Flag, und beide spielen ohne Fehler ein.

Wie prüfe ich den Dump, den ich schon habe?

Öffne ihn in einem Texteditor und suche nach auth. Was zurückkommt, ordnet deine Datei einer von drei Gruppen zu.

  1. Überhaupt keine Treffer. Das auth-Schema steht in dieser Datei in keiner Form. Das schreibt ein blankes supabase db dump.
  2. Treffer, aber nur in Zeilen, die mit CREATE, ALTER oder GRANT beginnen. Du hast den Entwurf des Gästebuchs und niemanden darin.
  3. Eine Zeile COPY "auth"."users" oder COPY auth.users, mit Datenzeilen darunter bis zu einer Zeile mit \. Oder eine Folge von Zeilen, die mit INSERT INTO "auth"."users" beginnen. Deine Konten sind drin.

Wenn du es lieber auf der Kommandozeile machst, beantworten zwei greps dieselbe Frage:

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

Der erste sagt, ob das Schema die Datei überhaupt erreicht hat. Der zweite sagt, ob die Personen es getan haben. Eine Null von beiden, bei einer Datei, auf die du gezählt hast, findest du besser heute heraus als an dem Morgen, an dem du sie brauchst.

Suche bei der Gelegenheit auch nach storage und lies genau, was du findest. Diese Zeilen sind die Liste deiner hochgeladenen Dateien, und das ist etwas anderes als die Dateien, denn kein Datenbank-Backup auf irgendeinem Tarif enthält die.

Wie exportiere ich Supabase-auth-Nutzer?

Mit dem Datenbefehl, der ein anderer Befehl ist als der, der das Schema schreibt.

Supabases Anleitung zu Backup und Wiederherstellung veröffentlicht das Backup als drei Dateien, und es lohnt sich, sie zusammen zu sehen, weil die Form davon die Antwort ist:

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"

Die zweite Zeile ist die, die allein ausgeführt wird. Die dritte ist die mit deinen Nutzern darin.

Diese beiden Tatsachen sehen aus wie ein Widerspruch und sind keiner. Der Satz auf Supabases Referenzseite über das Ausschließen von auth beschreibt den Schema-Dump, und der Daten-Dump läuft auch durch dieses Schema.

Willst du nur die Konten, dann benenne das Schema und du bekommst allein diese Schublade:

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

Bevor du dich auf eines davon verlässt, hänge --dry-run an und lies, was zurückkommt. Es druckt den pg_dump-Befehl, den das Werkzeug ausführen würde, ohne ihn auszuführen, sodass du selbst siehst, welche Schemas auf deiner installierten Version enthalten und welche ausgeschlossen sind. Lies diese Ausgabe einmal und du musst nie wieder diesem Artikel glauben, oder irgendeinem anderen, was zählt, weil die Flags sich zwischen Releases bewegen und die Datei so oder so gleich aussieht.

Es gibt auch den direkten Weg, und dafür ist ein schlichtes pg_dump da: benenne die Schubladen, die du willst, und es nimmt sie.

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

Eines noch zur Schema-Datei, weil es erklärt, warum das überhaupt aufgeteilt ist. Ein neues Supabase-Projekt kommt mit einem bereits gebauten auth-Schema, in der Version, die der Anmeldedienst heute fährt. Die Version deines alten Projekts darüberzuspielen würde einen älteren Entwurf auf einen funktionierenden legen. Hinüberbringen willst du den Inhalt des Gästebuchs, und den hält die Datendatei.

Was beim Zurückspielen der Nutzer kaputtgeht

Zwei Dinge, und Supabase dokumentiert beide.

Trigger, die eine Spalte zweimal verschlüsseln können. Der Wiederherstellungsbefehl in Supabases Anleitung hat mittendrin eine Anweisung, die man leicht für Beiwerk hält:

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

Diese mittlere Zeile schaltet die Trigger für die Dauer ab, und die Anleitung sagt, sie ist dafür da, Spalten beim Einspielen nicht ein zweites Mal verschlüsseln zu lassen. Spiel eine Datendatei ohne sie ein, und die Passwörter kommen bereits verwürfelt an von einem Vorgang, der schon auf sie angewendet worden war, und nichts danach macht das rückgängig.

Eigentümer und Rechte, die das Einspielen anhalten. Ein Dump aus einem Supabase-Projekt trägt Zeilen, die sich auf Rollen beziehen, an die dich das neue Projekt nicht lässt. Supabases Hinweise zur Fehlersuche für dieselbe Anleitung sagen, jede Zeile mit ALTER ... OWNER TO "supabase_admin" in schema.sql auszukommentieren, und eine bestimmte Zeile GRANT "postgres" TO "cli_login_postgres" in roles.sql. Beides ist eine Textänderung vor dem Start, und beides hält das Einspielen an, mit der Zeile, an der es hängen blieb, auf deinem Bildschirm.

Müssen sich meine Nutzer neu anmelden?

Ihre Passwörter kommen mit. Ihre Sitzungen nicht, außer du nimmst noch etwas mit.

Supabase sagt, du kannst jede Tabelle im auth-Schema migrieren, Nutzer und ihre gehashten Passwörter eingeschlossen, sodass niemand ein Passwort zurücksetzen muss, das er schon hatte. Kein Passwort ist dabei an irgendeiner Stelle lesbar; was umzieht, ist sein Hash.

Eine Sitzung ist etwas anderes. Sie wird durch ein Token belegt, das mit dem eigenen JWT-Secret deines Projekts signiert wurde, und jedes Projekt hat sein eigenes. Supabase sagt, dass jedes Token, das schon im Browser von jemandem liegt, ungültig wird und die Person sich neu anmelden muss, wenn das neue Projekt mit einem anderen Secret signiert. Du kannst das vermeiden, indem du das Secret des alten Projekts im neuen setzt, und auf derselben Seite steht der Preis dafür: Ein Wechsel des JWT-Secrets erzeugt die anon- und service_role-Schlüssel dieses Projekts neu, sodass deine App die neuen bekommen muss, bevor sie mit irgendetwas reden kann. Welcher Schlüssel welcher ist, und welcher davon überhaupt in deine App gehört, ist das, worüber du sicher sein willst, bevor du einen von beiden einfügst.

Die ehrliche Fassung lautet also, dass eine Wiederherstellung meist alle einmal zur Anmeldung bittet. Das ist eine Support-Mail. Es ist kein verlorenes Konto, und der Unterschied zwischen beidem ist, ob das auth-Schema in deiner Datei war.

Drei Dinge sind trotzdem nicht darin, was immer du mit den Flags machst. Deine hochgeladenen Dateien, weil Storage die Bytes außerhalb der Datenbank hält und kein Dump auf irgendeinem Tarif sie erreicht. Deine Edge Functions, die ein eigener Download sind und deren Import Maps laut Supabase nicht automatisch geholt werden. Und die Einstellungen deines Projekts, die Konfiguration und keine Daten sind und von Hand neu eingetragen werden.

Was diese Woche zu tun ist

Was zu tun ist

  • Nimm die neueste Backup-Datei, die du hast, und suche darin nach auth. Gruppe eins, zwei oder drei aus dem Abschnitt oben, und du weißt es in einer Minute.
  • Ist es Gruppe eins oder zwei, zieh heute einen Daten-Dump mit --data-only und --use-copy, und leg ihn neben die Schema-Datei statt an ihre Stelle. Du brauchst beide.
  • Häng --dry-run an den Befehl, für den du dich entscheidest, und lies die Ausgabe einmal, damit du weißt, welche Schubladen deine Version des Werkzeugs nimmt.
  • Schreib dir die Reihenfolge der Wiederherstellung dorthin, wo du sie wiederfindest: roles, dann schema, dann SET session_replication_role = replica, dann data.
  • Spiel einmal in ein Wegwerf-Projekt ein und versuch dann, dich als echter Nutzer anzumelden. Das ist die einzige Prüfung, die das testet, worum es in diesem Artikel geht.

Das einmal von Hand zu tun lohnt sich, egal wie du am Ende sicherst, denn solange du keinen Dump geöffnet hast, hattest du immer nur das Wort Backup. Ob du es weiter von Hand machst, ist eine eigene Frage, und die drei Wege und was jeder kostet ist der Ort, an dem die beantwortet wird.

Wo Reeve Care hineinpasst

Care zieht die Kopie nach Plan, und das Gästebuch ist darin.

Die Kopie hält deine Tabellen und deine Konten. Die Wiederherstellungs-Schaltfläche spielt deine Tabellen zurück und lässt die Konten, wo sie sind.
  • Deine Konten sind in der Kopie. Das auth-Schema reist mit deinen eigenen Tabellen, denn eine Kopie einer Supabase-App ohne ihre Nutzer ist eine Kopie der Hälfte. Die storage-Zeilen, die deine Dateien beschreiben, kommen mit, und die Dateien selbst ebenfalls, sobald du eine Storage-Zugangsinformation hinterlegst.
  • Die Wiederherstellungs-Schaltfläche spielt deine Tabellen zurück und lässt die Konten in Ruhe. auth.users über ein laufendes Projekt zu spielen meldet alle ab und bringt Konten zurück, die jemand absichtlich gelöscht hat, also bleibt das eine Anfrage mit einem Menschen daran. Ein Druck auf die Schaltfläche in Panik kann also nicht die Kunden abmelden, denen du helfen wolltest.
  • Die Kopie wird zurückgelesen, bevor sie als gezogen gilt. Das Datum in deinem Dashboard ist der letzte Zeitpunkt, an dem eine Kopie geöffnet und geprüft wurde, nie der Start eines Jobs oder die Ankunft einer Datei.
  • Eine Wiederherstellung macht zuerst eine Aufnahme des jetzigen Stands, sodass sie selbst ein Rückgängig hat.

Care beginnt bei €49 im Monat für eine App. Das ist ein Listenpreis, und die Preisseite liegt manchmal unter der Zahl hier und nie darüber.

Wie eine Kopie gezogen, geprüft und zurückgespielt wird, ist Schritt für Schritt auf der Supabase-Backups-Seite gezeichnet.

Bevor du diesen Tab schließt, öffne deinen neuesten Dump und suche darin nach auth. Das ist der schnellste Weg herauszufinden, ob dir das, was du Backup genannt hast, deine Kunden zurückgeben würde, und wenn die Antwort nein lautet, ist eine richtige Wiederherstellung das Nächste zum Lesen.

FAQ

Enthält ein Supabase-Backup meine Nutzer?

Das hängt davon ab, welcher Befehl die Datei geschrieben hat. Deine Nutzer liegen in einem Schema namens auth, das dem Anmeldedienst gehört. Ein blankes supabase db dump lässt auth weg und enthält überhaupt keine Zeilen, weil der Standard-Dump nur das Schema ist. Die Datenhälfte des Dumps, ein zweiter Befehl mit dem Flag --data-only, ist die, die deine Nutzer trägt. Genau deshalb veröffentlicht Supabase das Backup als drei Befehle.

Warum fehlt auth.users in meinem Dump?

Weil du mit ziemlicher Sicherheit den Schema-Dump ausgeführt hast. Supabase dokumentiert, dass der Befehl die verwalteten Schemas ausschließt, dass zu den ignorierten auth und storage gehören, und dass der Standard-Dump gar keine Daten enthält. Das ist Absicht: Ein neues Projekt kommt mit einem eigenen, vom Anmeldedienst gebauten auth-Schema, und eine ältere Kopie darüberzuspielen würde etwas ersetzen, das funktioniert. Umziehen soll der Inhalt, und den trägt der Daten-Dump.

Wie exportiere ich Supabase-auth-Nutzer?

Mit dem Datenbefehl, der vom Schemabefehl getrennt ist. Führe supabase db dump mit --data-only und --use-copy aus, um eine Datendatei zu schreiben, und die auth-Tabellen kommen mit. Willst du nur die Konten, dann füge --schema auth hinzu und bekommst eine Datei mit ausschließlich diesem Schema. Bevor du dich auf eines von beiden verlässt, hänge --dry-run an: Es druckt den pg_dump-Befehl, den die CLI ausführen würde, ohne ihn auszuführen, sodass du auf deiner Version nachlesen kannst, welche Schemas enthalten sind.

Überstehen Passwörter eine Supabase-Wiederherstellung?

Ja, wenn das auth-Schema in der Datei war. Supabase sagt, du kannst jede Tabelle im auth-Schema migrieren, gehashte Passwörter eingeschlossen, sodass niemand sie zurücksetzen oder neu anlegen muss. Ruinieren kann sie nur eines: die Daten einzuspielen, ohne vorher die Trigger abzuschalten. Deshalb setzt Supabase SET session_replication_role = replica mitten in seinen eigenen Wiederherstellungsbefehl. Lässt du die Zeile weg, wird eine bereits verschlüsselte Spalte beim Einspielen ein zweites Mal verschlüsselt.

Bleiben meine Nutzer nach einer Wiederherstellung angemeldet?

Nicht, wenn das neue Projekt mit einem anderen Secret signiert. Eine Sitzung wird durch ein Token belegt, das mit dem JWT-Secret des Projekts signiert wurde, und Supabase sagt, dass ein neues Secret vorhandene Tokens ungültig macht, sodass sich alle neu anmelden. Du kannst das alte Secret mitnehmen und alle angemeldet lassen, aber Supabase sagt auch, dass ein Wechsel des JWT-Secrets die anon- und service_role-Schlüssel in diesem Projekt neu erzeugt, sodass deine App die neuen braucht.

Was lässt ein Supabase-Dump sonst noch weg?

Deine hochgeladenen Dateien, vor allem. Storage hält für jede Datei eine Zeile in deiner Datenbank und die Datei selbst woanders, also enthält kein Datenbank-Dump auf keinem Tarif die Bytes. Edge Functions sind ein eigener Download, und Supabase merkt an, dass Import Maps und deno.json-Dateien nicht automatisch geholt werden. Projekteinstellungen, Auth-Provider und Secrets sind Konfiguration und keine Daten und liegen im Dashboard, also werden sie in einem neuen Projekt von Hand neu eingetragen.

Geschrieben von

Vlad Tkachenko

Gründer, Reeve

Ich schaue mir den ganzen Tag Apps an, die mit Lovable, Bolt, v0, Cursor und Replit gebaut wurden, und die kurze Liste von Fehlern, die darin immer wieder auftauchen.

Mehr über den Autor

Weiterlesen

Alle Artikel

Unsicher, wie es um deine eigene App steht?

Starte einen kostenlosen Scan und erhalte in rund 20 Sekunden eine verständliche Note von A bis F. Ohne Konto, ohne Karte.

App kostenlos scannen

Automatisierte externe Prüfung, kein vollständiges Audit. Das Fehlen von Funden ist keine Garantie für Sicherheit.