Your database already has backups. They live in the same account
Automated backups, snapshots and replicas all answer to the credentials that run the database. That covers the failure you plan for and none of the ones that end companies. This is the second copy, somewhere the first one’s bad day cannot reach.
No card required. Runs alongside what you already have.
Two different jobs, and you want both
We are not asking you to turn off your managed backups. They are better than us at the top of this table and structurally cannot help with the bottom of it.
| When this happens | Managed backups | saved.sh |
|---|---|---|
| Someone drops a table | ||
| A migration corrupts a column | ||
| You need the state at 14:32:07 exactly | ||
| The database instance is deleted | ||
| The cloud account is compromised | ||
| Ransomware with admin credentials | ||
| The provider suspends the account |
Row three is the one we lose, and it matters: point-in-time recovery replays a transaction log and can land you on an exact second. We take periodic logical backups, which is a coarser instrument. Keep theirs for the dropped table. Keep ours for the day the account is gone.
The question is who holds the connection string
All three produce the same artifact under the same encryption and the same retention. What varies is custody of the credential, and you should pick the least you can live with.
01
Push from your own automation
You already run pg_dump somewhere. Pipe it to the CLI and we never see the connection string at all.
We hold nothing
02
A worker on your hardware
We hold the schedule and drive it; the worker connects to the database locally. The credential lives in that worker's config and our API rejects it if you try to send it to us.
We hold the schedule
03
Fully managed
Hand over a connection and we execute it. The payload goes to a secrets manager and is released only to the run that needs it.
We hold a credential
A backup is a file you commit
Name, source, schedule, retention and a key fingerprint. Apply it and reconcile it like any other infrastructure, or click through the dashboard if you would rather. Anything in one is in the other.
saved.yaml
backups:
- name: prod-db
kind: local
sourceType: postgres
worker: prod-worker-1
schedule: "0 2 * * *"
retention:
keepLast: 10
expireAfter: 90d
lockFor: 30d
encryptionPublicKey:
valueFrom:
file: ./keys/prod.asc$ saved apply -f saved.yaml
Three settings, and one of them is a promise
Keeping and protecting are different axes, and most products conflate them. Loosening a cleanup rule should not be able to unprotect what you already stored.
keepLast
How many copies we keep for you. Cleanup, not protection: lowering it deletes the extras on the next sweep.
expireAfter
When we delete for you. Also cleanup. Together with keepLast it is what bounds your storage bill.
lockFor
How long nobody may delete, you included. Stamped onto each artifact as it is written, and it can be lengthened but never shortened.
The limit, stated where you will see it: the hold is enforced in our code, so it binds every path through our API and our own sweep, and it does not bind someone holding our storage credentials. The security page says exactly where that stops.
Retention is the lever, not frequency
Archive dominates a database backup bill, and archive scales with how many copies you keep rather than how often you take them. Running hourly instead of daily multiplies three small meters. Keeping ninety days instead of thirty triples the large one.
You are billed on what is stored, so a 20 GB database that compresses 4x is 5 GB per copy on the meter.
What you need
- A reachable Postgres instance
- A worker on your hardware, or a connection you will hand over
- A GPG public key uploaded to the workspace
Postgres is the relational source shipped end to end today. MySQL and Redis are announced rather than available, and a script source covers anything not on the list with the same guarantees.