Skip to content

Restore to a point in time

Goal: Bring a database back to the state it was in at a specific moment in the past — useful for recovering from accidental deletes, bad migrations, or data corruption.

Prerequisites:

  • A Pro or Business project with a dedicated managed Postgres.
  • A target timestamp within the retention window (Pro: last 30 days, Business: last 90 days, minus a small lag buffer on both ends).

PITR is Pro+ only. Hobby and Dev tiers do not support point-in-time recovery — requests are rejected with 403 tier_required.

Requesting a restore does not touch your live database. uploy creates a parallel cluster from the archived base backup plus WAL replay up to your chosen timestamp. Once it’s ready, you decide:

  • Promote — the parallel cluster becomes the live database. The injected DATABASE_URL is rewritten; your apps reconnect automatically. The previous cluster is deleted.
  • Discard — the parallel cluster is deleted; your live database is unchanged.

Only one restore can be pending per database at a time.

  1. Open the project → Database tab → the database you want to restore.
  2. Click Restore. A dialog opens.
  3. Choose Point in time.
  4. Pick a timestamp. The date/time picker’s min and max are bound to your tier’s valid window; anything outside returns 400 invalid_timestamp.
  5. Click Submit.
  6. A Restore pending banner appears. It shows when you requested the restore and the name of the parallel cluster being built. Wait for the parallel cluster to become ready (typically a few minutes).
  7. When ready, the banner offers two buttons:
    • Promote — you are prompted to confirm. Clicking Continue swaps in the restored cluster. Apps reconnect on their next database request.
    • Discard — deletes the parallel cluster. Your live database is untouched.
  • After Promote: the database’s cluster name in the UI reflects the restored cluster, and the Restore pending banner disappears. Your app’s logs show it reconnecting to the database.
  • After Discard: the banner disappears; nothing else changes.
  • The window starts one hour after the oldest base backup (buffer for base-backup lag).
  • The window ends one minute before the current time (buffer for WAL archival lag).
  • If the exact moment matters (e.g. right before a bad migration), pick a time just before the incident; you can always request another restore if you overshoot.
  • One pending restore per database. Requesting a second one while the first is pending returns 409 restore_pending.
  • Retention determines the earliest point you can reach: 30 days on Pro, 90 days on Business.
  • Promote is destructive with respect to writes that happened after your chosen timestamp — they are not preserved. Download a backup or take an application-level snapshot first if you want to keep them.

If the restore-pending banner doesn’t progress to a ready state, see Restore stuck in pending.