Backups (Litestream)
Litestream is a sidecar that streams WAL changes from SQLite to S3 (or any S3-compatible bucket) continuously. RustBaas ships first-class integration: turn it on in rustbase.toml, point it at a bucket, and your system.db, every realm.db, and every app data.db are replicated.
Why Litestream
SQLite snapshots are atomic at file-copy boundaries. Litestream pipes the WAL out as it's written, so:
- RPO (recovery point objective) is sub-second.
- RTO (recovery time objective) is "download the bucket, restart RustBaas."
- Cost is tiny — object storage + a few KB/s of egress.
For a single-node BaaS that lives or dies by its SQLite files, this is the right backup model.
Turning it on
[litestream]
enabled = true
bucket = "s3://my-rustbase-backups"
prefix = "prod"
replicate_interval_sec = 10When enabled = true, RustBaas on boot:
- Walks
data/for every*.dbfile. - Generates
data/litestream.ymlwith one entry per DB. - Starts Litestream as a child process and forwards its logs into RustBaas's tracing output.
You don't run Litestream yourself — RustBaas manages it.
Bucket layout
s3://my-rustbase-backups/
prod/
system.db/
generations/<id>/snapshots/...
generations/<id>/wal/...
realms/acme/realm.db/
generations/<id>/...
realms/acme/apps/web/data.db/
generations/<id>/...The on-disk path becomes the prefix in the bucket. Adding a realm or app on disk → next replication cycle catches it automatically.
Credentials
Litestream uses standard AWS-style env vars:
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1For Cloudflare R2 / Backblaze B2 / MinIO, also set:
AWS_ENDPOINT_URL_S3=https://<account>.r2.cloudflarestorage.com(See Litestream's S3 endpoint docs.)
Restoring
- Provision a fresh host, install the
rustbasebinary, and create thedata/directory. - Install the
litestreamCLI on the host. - For each DB you want to restore, run:shDo the same for every
litestream restore \ -o data/system.db \ s3://my-rustbase-backups/prod/system.dbrealm.dband every appdata.db. - Copy the matching
data/realms/<realm>/apps/<app>/storage/(the file blobs) from wherever you mirrored them. If you used the S3 storage backend, this step is automatic — the blobs already live in S3. systemctl start rustbase.
That's the entire DR drill.
RPO / RTO targets
| Component | Backed up by | RPO | RTO |
|---|---|---|---|
system.db + every realm.db + every data.db | Litestream → S3 | replicate_interval_sec (default 10s) | Minutes to download + restart |
| File blobs (local backend) | Your own rsync / restic | Whatever you set | Minutes |
| File blobs (S3 backend) | S3 itself | — | — |
| Hooks (JS/TS source) | Your version control or your rsync | Whatever you set | Seconds |
Hooks aren't replicated by Litestream because they're not databases. Treat them like application code — version-control them.
What about write failover?
There isn't one. SQLite is a single-writer database; replicas are passive. If the primary host dies, you restore to a new host. That's the model.
If you need a hot failover with sub-second cutover, RustBaas is not the right shape — you want a Postgres cluster.
Disabling
Set enabled = false (or delete the [litestream] section) and restart. RustBaas shuts the sidecar down and doesn't recreate data/litestream.yml. Existing data in the bucket stays put until you clean it up.