How to safely restore a Supabase backup without reactivating revoked permissions or external jobs? #51810
Replies: 6 comments 5 replies
|
Hey David, you don't need to build heavy custom infrastructure for this. You can handle almost all of this natively using Supabase's Restore to a new project workflow combined with a lightweight "tombstone" log and RLS. Here is how I'd structure it as a solo dev:
-- Pause all scheduled pg_cron jobs
SELECT cron.alter_job(jobid, active => false) FROM cron.job;
Point-in-Time Recovery (PITR): If budget allows later on, PITR streams WAL logs continuously, so you restore to the exact second before the incident on Wednesday instead of losing 48 hours. A zero-maintenance Tombstone Log (if using daily backups): In 95% of real-world "bad migration / accidental delete" incidents, your Wednesday DB is still readable. You can query the Wednesday DB directly (or via postgres_fdw) to diff which user_ids were deleted or had consent/group membership revoked since Monday, and replay those deletions on the restored project. To cover a total Wednesday DB outage without building extra servers, just fire a tiny append-only log (only UUIDs + action + timestamp, zero PII: {"op": "revoke_consent", "user_id": "...", "ts": "..."}) to an external bucket (like S3/R2) or even a single table on a separate free-tier Supabase project whenever a user deletes their account, gets removed from a group, or revokes consent.
CREATE POLICY "Active members only"
ON public.group_memberships
FOR SELECT
USING (
auth.uid() = user_id
AND needs_revalidation = false
);During recovery, before re-enabling Supabase Cron and pointing your app to the restored database, you run a single UPDATE to flag any memberships/consents that need re-confirmation, and RLS will safely block access until the user revalidates in the Android app. |
|
Thanks for the detailed explanation! There's one point I'm still concerned about. According to the Supabase documentation, If I disable them afterward, some external actions might already have occurred. For example:
Is there a supported way to prevent these jobs from running before the restored database becomes active? That's the main safety guarantee I'm trying to achieve. Thanks again! |
|
Restoring into a separate place first is the right instinct, and the tombstone log devcaiada described is the piece I'd try. Two things from doing this on our own projects: Take your own logical dump as well. Then rehearse it on a schedule. Monthly is plenty for a solo project: restore, replay, and check that a deleted account is still deleted and a revoked membership is still gone. The first rehearsal usually turns something up (an extension that didn't come back, a sequence behind the data). |
|
The instinct to isolate before reconciling is the right one, and Supabase's supported primitives get you most of the way without extra infrastructure. What a restore actually is A PITR restore or a The supported flow
The honest limitation Consent revocations that you did not log cannot be reconstructed from a backup — the backup does not know they happened. That is not a Supabase limitation, it is what a backup is. For your specific case (user consent), the fix forward is the audit table above, plus writing consent state as an append-only event log rather than a mutable flag, so "user revoked consent at T" is a fact you hold independently of any restorable snapshot. What I would do concretely, small app, solo PITR is your friend here: enable it, and when you need recovery, restore to a new project at the backup timestamp rather than overwriting the live one. Reconcile the delta between new-project-restored and live (both readable at once, so the comparison is a script, not a memory exercise), then flip the env. That keeps the blast radius of step 3 contained and gives you the "keep uncertain permissions disabled until revalidated" behaviour you asked for — uncertain rows are simply the ones your reconciliation script could not match, and you leave them inactive until you look at them. One more thing for the solo-maintainer case: the restore-verification steps 1–4 are a checklist, not a one-off, and they belong in the same repo as your migrations so the next person (or you, at 3am) runs them in order. The failure mode of DR is not the restore, it is the restore plus the assumption that everything after the backup point still applies. |
|
Thank you all for taking the time to reply and explain things so clearly. I really appreciate your help! I'm going to test a small, independent project acting as a fail-closed switch for outbound calls during recovery, alongside an isolated restore and a separate deletion registry. The main challenge is making sure nothing unsafe can happen before reconciliation, including cron jobs and database operations that might bypass the switch. If anyone is interested in the results, just let me know and I'll happily share them here. Thanks again. |
|
On the cron and webhook part: a restore into a new project can bring those back paused. ReviveDB restores a recovery point into a separate, empty Supabase project with the For the deletion registry, each recovery point records https://revivedb.dev (I build ReviveDB) |
Uh oh!
There was an error while loading. Please reload this page.
Hi everyone,
I'm evaluating Supabase as the backend for a small Android application with user accounts, private groups, memberships, invitations, and user consent settings.
I have a concern about disaster recovery.
Imagine restoring Monday's database backup on Wednesday. In the meantime, some users deleted their accounts, others were excluded from groups, and some revoked their consent.
Restoring the backup could unintentionally reactivate those accounts and permissions.
Ideally, I'd like to restore the database in an isolated environment, prevent APIs and background jobs (cron, webhooks, etc.) from running, then reapply known deletions and keep uncertain permissions disabled until they can be safely revalidated.
Is there a safe, supported way to do this with Supabase, or a simpler approach you would recommend?
I'm working alone, so I'd like to avoid building unnecessary infrastructure.
Thanks for your advice !
David
All reactions