Daily snapshot backups have a recovery point objective (RPO) of up to 24 hours — a catastrophic failure late in the day can erase a full day of transactions, orders, or user data. Point-in-time recovery compresses that window to minutes. ISO 25010 recoverability requires that the system can be restored to a recent-enough state to be operationally viable; for applications handling financial transactions, bookings, or communications, 24-hour data loss is not viable. Supabase Free tier provides only basic daily backups — many teams on free tier assume PITR is included until they need it.
Medium because PITR absence means up to 24 hours of data loss in a disaster, which is tolerable only for applications with no financial or time-sensitive records.
Verify your database platform plan includes PITR and document the recovery window. For Supabase, upgrade from Free to Pro. For self-hosted Postgres, enable WAL archiving.
# postgresql.conf — enable WAL archiving for self-hosted Postgres
wal_level = replica
archive_mode = on
archive_command = 'aws s3 cp %p s3://myapp-wal-archive/%f'
# Neon — branch from a specific timestamp (PITR via branching)
neon branches create --from-timestamp 2024-01-15T10:30:00Z
# AWS RDS — configure retention period
aws rds modify-db-instance \
--db-instance-identifier mydb \
--backup-retention-period 7
For Supabase: Pro plan ($25/month) enables daily PITR. Team plan ($599/month) enables per-minute PITR. Access PITR via Supabase Dashboard > Settings > Backups > Point in Time Recovery.
ID: database-design-operations.backup-recovery.point-in-time-recovery
Severity: medium
What to look for: Enumerate every backup mechanism configured and determine whether PITR is configured for the production database. For managed databases: Supabase provides PITR on Pro and Team plans (daily snapshots + WAL on Pro, every minute on Team). Neon provides "branch from any time" via its branching system. PlanetScale provides Restore from backup UI. AWS RDS has PITR enabled by default with a configurable retention window (default 1 day, max 35 days). Google Cloud SQL has similar PITR. For self-hosted Postgres: look for WAL archiving configuration (archive_mode = on, archive_command) in Postgres config or the infrastructure provisioning files. Check if the project is on a database plan that includes PITR or if they're relying solely on daily snapshots (which means up to 24 hours of data loss in a disaster).
Pass criteria: At least 1 PITR mechanism is enabled for the production database. The project is on a managed platform plan that includes PITR, or WAL archiving is configured for self-hosted Postgres. Recovery objective (RPO) of less than 1 hour is achievable.
Fail criteria: No PITR available. Only daily snapshots exist with a potential RPO of up to 24 hours. Project is on a Supabase Free tier that provides only basic backups without PITR. Self-hosted Postgres with no WAL archiving.
Skip (N/A) when: Development-only project not yet in production. Or SQLite database (PITR is not applicable — use regular file backups). Or application has no data that would require granular point-in-time recovery.
Detail on fail: Specify what PITR coverage is missing. Example: "Project uses Supabase Free tier — no PITR available, only daily snapshots. Data loss of up to 24 hours is possible in a disaster." or "Self-hosted Postgres with no WAL archiving configured — only pg_dump backups exist.".
Remediation: Enable PITR for your database platform:
Supabase:
- Upgrade to Pro plan ($25/month) to get daily PITR
- Upgrade to Team plan ($599/month) to get per-minute PITR
- Access PITR: Supabase Dashboard > Settings > Backups > Point in Time Recovery
AWS RDS:
- PITR is enabled by default
- Configure retention: aws rds modify-db-instance --db-instance-identifier mydb
--backup-retention-period 7 (7 days, max 35)
Neon (branching as PITR):
- Create a branch from any timestamp: neon branches create --from-timestamp 2024-01-15T10:30:00Z
- Restore by promoting the branch or migrating data from it
Self-hosted Postgres — enable WAL archiving:
# postgresql.conf
wal_level = replica
archive_mode = on
archive_command = 'aws s3 cp %p s3://myapp-wal-archive/%f'