TL;DR: A disaster recovery plan ensures your SaaS survives data loss, corruption, or provider outages. This guide covers automated D1 backups to R2, point-in-time recovery strategies, backup integrity verification, and a runbook for restoration.
Introduction
Data loss isn't a matter of if, but when. A misconfigured migration, a bug that corrupts data, or a provider outage can destroy months of user data. A proper backup and disaster recovery plan is your insurance policy.
Automated Backups with Cron Triggers
// src/server/backup.ts
import { createServerFn } from '@tanstack/react-start'
export const runDatabaseBackupFn = createServerFn({ method: 'POST' })
.handler(async ({ context }) => {
const env = context.env
const timestamp = new Date().toISOString()
const backupKey = `backups/db/${timestamp}.sqlite`
// Export D1 database
const result = await env.DB.dump()
// Store in R2
await env.R2.put(backupKey, result.body, {
customMetadata: { timestamp, type: 'full' },
})
// Clean up old backups (keep last 7 days)
await cleanOldBackups(env.R2, 'backups/db/', 7)
return { backupKey, timestamp }
})
Backup Strategy Matrix
| Backup Type | Frequency | Storage | Retention | Recovery Time |
|---|---|---|---|---|
| Full database | Daily | R2 | 30 days | 30 minutes |
| Transaction log | Continuous | D1 | 7 days | 1 minute |
| File assets | On change | R2 versioning | 90 days | Instant |
| Configuration | On change | Git + KV | Indefinite | 10 minutes |
Conclusion
Automate your backups with Cloudflare Cron Triggers. Store in R2 for durability. Test your restore process monthly. A backup you haven't tested restoring from isn't a backup at all. For deeper context, see our Cloudflare R2 Object Storage Guide, D1 Production Guide, Cron Triggers documentation, and SaaS Security Best Practices.