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:
prodis protected. A restore of aprodchannel is a protected action. You can always restoreprodyourself 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 with403 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
- 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.
- Write migrations that work against a table with rows: add a
NOT NULLcolumn with aserver_default, and useCREATE INDEX CONCURRENTLY. - Test the change in a preview environment first. A preview has its own database, so it cannot harm production. See Preview and staging environments.
- Download a dump before any risky change to production data.
- 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.