Every managed database provider takes automatic backups, says so on the pricing page, and is telling the truth. Then a team reads that line, ticks the backup box on their compliance questionnaire, and stops thinking about it.
The gap between "the provider takes snapshots" and "we have backups" is where most of the bad days live.
What a provider snapshot actually is
A provider snapshot is a copy of your data, held by the provider, in the provider's own format, inside the provider's account, restorable only into that same provider.
Read that sentence again with an incident in mind. Every clause is a dependency on the exact organisation whose failure you are trying to survive.
| Scenario | Provider snapshot | Portable dump in your bucket |
|---|---|---|
| You dropped a table | Works well, often the fastest option | Works |
| Provider has a regional outage | Unavailable exactly when needed | Works |
| Your account is suspended or the payment fails | Usually inaccessible | Works |
| You want to move to another provider | Not restorable elsewhere | Works |
| An auditor asks for a copy outside the vendor | Cannot produce one | Works |
| Someone deletes the instance | Snapshots frequently go with it | Works |
Provider snapshots are genuinely good at the first row. They are structurally incapable of the rest, and no amount of provider durability changes that, because durability was never the problem. Custody was.
The fix is a logical dump you own
For anything Postgres-compatible, which now covers Neon, Supabase, RDS, and most of the newer entrants, the portable copy is a logical dump:
pg_dump "$DATABASE_URL" \
--format=custom --no-owner --no-privileges \
| gzip -9 \
| aws s3 cp - "s3://${BUCKET}/pg/$(date -u +%Y-%m-%dT%H-%M-%SZ).dump.gz"--no-owner and --no-privileges matter more here than on self-hosted Postgres.
Managed providers invent their own role names, and a dump that carries them will
fail to restore anywhere except back into the same provider, which defeats the
entire point.
For MySQL-compatible providers including PlanetScale, the equivalent is
mysqldump --single-transaction --set-gtid-purged=OFF, where the second flag is
what stops the dump refusing to load into a different topology.
1
Row in that table a snapshot covers
5
Rows it does not
2flags
Between a portable dump and a stuck one
Where the connection-limit problem bites
Serverless Postgres providers pool aggressively and cap connections, and a long
pg_dump holds one open for the duration. On Neon and Supabase specifically,
run the dump against the direct connection string rather than the pooled one.
The pooler will terminate a long transaction, and you will get a truncated dump
that exits zero.
That failure mode is worth stating plainly because it is the single most common way a managed-database backup is silently broken: the dump succeeds, the file lands, and it contains part of your data. A size comparison against the previous run catches it. Nothing else will.
What we do
We run exactly the dumps above, on a schedule, from a worker with the right network path to your database, and we write the result to a bucket you own.
The parts that are ours rather than yours are the parts that are annoying: holding the credential in a secret store instead of an env file, retrying a run that died halfway, recording what each run produced so a truncated dump shows up as a size anomaly instead of a surprise, and applying a retention policy that knows whether a newer good copy exists before it expires an older one.
The summary
Keep the provider snapshots. They are fast, they are cheap, and they are the right tool when someone drops a table at 11am.
Then add one portable dump, in an open format, in an account the provider does not control. That copy is the one that answers every other row in the table.