Your Supabase Backup Isn't Backing Up Your Files
Daily backups and PITR cover Postgres only — Storage objects, roles, config, and secrets are your problem.
There's a line buried in Supabase's backup docs that most teams discover only after something goes wrong: "Database backups do not include objects you store via the Storage API, as the database only includes metadata about these objects." Read that again. Every daily backup Supabase takes for you, and every Point-in-Time Recovery snapshot you pay $100 a month for, covers Postgres only. Your users' uploads — avatars, invoices, documents — are not in it.
This keeps surprising people because Supabase's architecture invites a mental shortcut. It's "just Postgres," so pg_dump plus a cron job feels like a complete answer. It isn't, and the gap between what that covers and what your project actually contains is where the pain lives.
Durability is not recoverability
When users asked about Storage backups on GitHub, Supabase's answer leaned on S3's eleven nines of durability. That's true and almost entirely beside the point. Durability protects you from AWS losing a disk. It does nothing when the threat is you: a buggy cleanup job, a migration that cascades deletes through storage.objects, a leaked service-role key. The same thread confirms the sharp edge plainly — deleted Storage files are permanently gone, and restoring a database backup will not bring them back.
Worse, a database-only restore actively lies to you. The storage.objects table is metadata; the files live in a separate S3-backed store. Restore yesterday's database and the metadata rows for since-deleted files reappear, pointing at objects that no longer exist. Your app looks healthy — lists render, counts match — until someone clicks a download link. That's the most dangerous kind of backup failure: the one you find during the incident, not the drill.
For scale: the Free tier has no automatic backups at all. Pro ($25/month) keeps 7 daily database backups, Team keeps 14, and PITR — built on WAL-G with WAL shipped every two minutes for a worst-case RPO of two minutes — is a $100/month add-on per 7 days of retention. All of it, database only.
Two stores, no atomic snapshot
Suppose you accept the split and run two jobs: supabase db dump for the database, rclone syncing your buckets offsite (Supabase Storage exposes an S3-compatible endpoint — enable it under Storage settings, then rclone treats it like any other S3 remote). You're now most of the way there, but the two jobs are separate operations against a live system. There is no transaction spanning Postgres and Storage, so your "backup" is a pair of snapshots taken at different moments — a state that may never have existed.
You can't eliminate that skew, but you can choose which failure mode you get. Run the database dump first, then sync files. Uploads that land in between become orphaned files in your backup — wasted bytes, harmless. Run it the other way and those uploads become metadata rows pointing at files your copy doesn't have — broken links after restore. Since uploads outnumber deletes in almost every app, dump-then-sync is the right default. Deletions in the window can still leave dangling rows either way; if your app deletes objects aggressively, shrink the window by running the jobs back to back.
Two more practicalities. Syncing buckets out counts as egress — about $0.09/GB beyond your plan's quota — so a nightly full sync of a large bucket has a real invoice attached; rclone's incremental sync keeps it sane. And push the copy to a different provider (Cloudflare R2 and Backblaze B2 are the usual picks, both with cheap or free ingress). A backup living in the same blast radius as production, under credentials stored next to production's, is a replication scheme, not a backup.
What the dump still misses
Even the Postgres half has gaps a naive pg_dump won't cover. pg_dump never includes roles — they're cluster-level — so RLS policies referencing custom roles can fail on restore into a fresh project. The Supabase CLI handles this if you ask:
supabase db dump --role-only -f roles.sql
supabase db dump -f schema.sql
supabase db dump --data-only --use-copy -f data.sql
Beyond that sits the control plane, which no database dump touches: auth provider configuration, SMTP settings, redirect URLs, Edge Functions and their secrets. Keep Edge Functions in git (you deploy them from source anyway) and manage project settings declaratively via the CLI's config.toml so they're reconstructable. Vault secrets deserve a special warning: they're encrypted with a root key held by the platform, outside your database, so those rows are undecryptable ciphertext when restored anywhere else. Export anything critical through the Vault API separately.
And then the step everyone skips: restore. A green cron job proves a process exited zero, nothing more. Spin up a scratch Supabase project monthly, restore roles → schema → data, sync the bucket copy back, and click through the app. Thirty minutes of tedium, and it converts "we have backups" from a belief into a fact.
Supabase should own this
The verdict here is uncomplicated: this is a product gap, and the eleven-nines answer is a dodge. Requests for Storage backups synced with database backups have been open on GitHub since 2022, and a small cottage industry of paid third-party Supabase backup services now exists — always the clearest signal that a platform has left a hole where a feature should be. Firebase drew the same line between Firestore exports and Cloud Storage, so there's precedent, but Supabase's whole pitch is being the integrated, open alternative. An integrated platform that can't take an integrated backup — and whose recovery add-on costs 4× the base plan while still excluding files — is shipping its riskiest gap to its least-informed users.
Until that changes, the honest checklist is short: dump roles, schema, and data with the CLI; rclone your buckets to another provider, after the dump; keep functions and config in git; encrypt what leaves; and restore the whole thing somewhere disposable on a schedule. None of it is hard. All of it is on you.
Sources & further reading
- I thought backing up Supabase was just pg_dump + rclone. It wasn't. — dev.to
- Database Backups — supabase.com
- Are back-ups created for storage? — github.com
- Pricing — supabase.com
Priya covers AI frameworks, developer productivity tooling, and the startup ecosystem across South and Southeast Asia, bringing a researcher's rigour and a practitioner's empathy to every story. She is deeply sceptical of benchmarks and asks hard questions so her readers don't have to.
Discussion 0
No comments yet
Be the first to weigh in.