xhostd
Sign in Start building
← Concepts

Postgres backups and recovery on xhostd

xhostd backs up each Postgres database nightly and takes a snapshot before every deploy. See retention per plan and what a database restore does not cover.

xhostd automatically backs up the Postgres database of every channel that runs your code. It takes a database snapshot every night, and it takes another snapshot before each deploy, so you have a backup before deployment of any change that touches your data.

A snapshot is a database recovery point, not a continuous log. This article explains both kinds of Postgres backup, how long xhostd keeps them, and the limits of a PostgreSQL backup and restore. Read it before you rely on a particular recovery window.

The two kinds of database snapshot

Nightly snapshots. Once a day, xhostd snapshots each project's database and its files. A static project has no database, so it has nothing to snapshot.

Pre-deploy snapshots. Before every deploy of a channel that has a database, xhostd saves a snapshot, then starts the new container. The deploy log records the event as channel snapshot marker recorded. The snapshot holds the state immediately before that deploy changed anything, which gives a bad migration a known point to go back to.

How long xhostd keeps backups

Retention depends on the plan:

Plan Nightly snapshots Pre-deploy snapshots
Basic (free) and Starter (accounts an agent created) 24 hours Last 1
Builder, Indie, Studio, Pro 7 days Last 3

Two rules apply on top of the table:

  • xhostd always keeps a project's newest nightly snapshot, however old it is.
  • You can restore a snapshot only while it is inside the backup window, which reaches back about 14 days. xhostd keeps pre-deploy snapshots by count, so an older one can still appear in the list. The list marks it recoverable: false, and you cannot restore it.

The pricing page and the backup FAQ state the current figures. Your agent can also read them from get_account_overview.

Choose the right snapshot

Ask your agent to list a channel's snapshots. Each entry carries a snapshot_id, a created_at time, and a deploy_id. The deploy_id names the deploy the snapshot precedes. The snapshot marked with deploy B holds the data as it stood before deploy B ran, without B's migrations.

Choosing the snapshot with the right deploy_id matters more than choosing the newest one.

What a snapshot does not cover

It is not point-in-time recovery. You can go back to a snapshot, not to any second between two of them. Writes made after the snapshot are lost if you restore to it.

It does not restore your code. A database restore changes data only. If you restore to a state before a migration, deploy the commit that matches that state too. Otherwise the next container start runs the migration again. The rewind tool and a deploy of an older commit recover code, and neither one restores a database or files.

It does not always cover files and data together. The project's Data and recovery section in the console shows whether a file checkpoint is aligned with the database checkpoint. A checkpoint with no aligned file marker is not an atomic restore of the whole application.

It does not replace a copy that you hold. Download a pg_dump from the console, or call the dump endpoint of the API, and store it somewhere you control. Treat an export that is disabled, unavailable, or incomplete as no backup.

Restore a database snapshot

A database restore replaces the channel's data with the snapshot's data. These safeguards apply:

  • prod is protected. A restore of a prod channel is a protected action. You can always restore prod yourself in the console. An agent can restore it only while agent access is on for the project. The project owner turns agent access on in the console: on the project's Access page for that project, or on the Account & billing page for every project that follows the account default. Until then, xhostd refuses the agent's restore with 403 protected_action. The refusal is the guard working, not a fault.
  • A restore saves no snapshot of what it replaces. The rows it overwrites are not in the snapshot list afterward.
  • A restore waits for a deploy. xhostd refuses it while a deploy on the same channel is queued or in progress.
  • A failed restore loses nothing. The restore runs in one transaction, and the server rolls it back if any step fails.

xhostd can pause database restores while it changes how they run. A refused restore returns the code restore_unavailable. If you see it, contact support. The Data and recovery guide states the current status. File restores are separate.

A safe routine for Postgres hosting

  1. Keep migrations in the same commit as the code that needs them, and run them in the start command, so the pre-deploy snapshot precedes them.
  2. Write migrations that work against a table with rows: add a NOT NULL column with a server_default, and use CREATE INDEX CONCURRENTLY.
  3. Test the change in a preview environment first. A preview has its own database, so it cannot harm production. See Preview and staging environments.
  4. Download a dump before any risky change to production data.
  5. After any recovery, verify the application's behavior and its data. Do not assume a restore worked because the call returned.

The Postgres recipe shows the snapshot and migration flow with real deploy logs. To compare with running Postgres on your own server, see VPS vs. managed application hosting.