pgBackRest is the best open-source Postgres backup tool there is. Parallel backup and restore, incremental and differential modes, compression, encryption, delta restore, and — the feature that matters most — point-in-time recovery to any transaction, not to whenever your last dump ran.
If you run Postgres seriously and have not looked at it, look at it. This page is not an argument that it is the wrong tool.
It is an argument that the choice is physical versus logical, and that this distinction, not the feature list, decides which fits your situation. Most comparisons skip it, and it is the only part that really matters.
Physical and logical backups are different things
pgBackRest takes physical backups. It copies the actual data files in PGDATA — the on-disk pages — plus a continuous stream of write-ahead log segments via archive_command. Restoring means putting those files back and replaying WAL up to a chosen moment.
A pg_dump is a logical backup. It reads the database through SQL and writes out the schema and data as instructions to recreate them.
Everything below follows from that one difference:
| Physical (pgBackRest) | Logical (pg_dump) | |
|---|---|---|
| Recovery granularity | Any transaction | Whenever the dump ran |
| Typical RPO | Seconds | Hours |
| Restore speed on large DBs | Fast, parallel file copy | Slow — replays SQL, rebuilds indexes |
| Restore target version | Same major version only | Any version, usually newer too |
| Restore target platform | Same architecture | Anything running Postgres |
| Restore a single table | No — all or nothing | Yes |
| Usable for major upgrades | No | Yes |
Needs filesystem access to PGDATA | Yes | No |
Needs postgresql.conf changes + restart | Yes — archive_mode | No |
| Works with managed Postgres (RDS, Supabase, Neon) | Usually not | Yes |
| Detects logical corruption | No — copies corrupt pages faithfully | Dump fails or produces readable SQL |
What pgBackRest is genuinely better at
RPO measured in seconds. WAL archiving means the recovery point is the last archived segment, not the last dump. For a payments database, this difference is the entire argument, and no logical backup schedule closes the gap.
Restore speed at scale. Restoring a 2 TB database from a physical backup is a parallel file copy plus WAL replay. Restoring the same database from a logical dump means executing every INSERT and rebuilding every index — often hours longer. On large databases, physical wins the RTO comfortably.
Recovery to a specific moment. --target-time recovers to just before the bad migration ran. A nightly dump gives you "the night before," which may be fifteen hours of lost work.
Incremental backups of the database itself, at page level, rather than dumping the whole logical content each time.
Barman occupies similar ground with a different operational model; the physical-versus-logical trade-off below applies to it equally.
What the physical model costs you
Version and platform lock. A physical backup restores only into the same Postgres major version, on a compatible architecture. Postgres 15 files do not go into a Postgres 16 server. This means pgBackRest cannot help you upgrade, cannot move you to a different provider, and cannot restore onto a developer's machine running a different version. Logical dumps do all three.
It faithfully backs up corruption. Physical backup copies pages. A corrupted page is backed up as a corrupted page, and if the corruption predates your retention window, every copy has it. A pg_dump reads through the SQL layer, so it usually fails on corrupt data rather than silently preserving it — an unpleasant surprise that is much better received during a backup than during a restore.
Configuration access is mandatory. You need archive_mode = on, an archive_command, a restart, and filesystem access to PGDATA. On RDS, Supabase, Neon or any managed Postgres, you do not have those, which rules pgBackRest out entirely for a large and growing share of deployments.
You run the repository. A host or bucket, with monitoring, capacity planning, and its own backup story. And the common configuration puts that repository in the same cloud account as the database — which protects against a failed disk and not against losing the account.
Operational surface. archive_command failing silently is a classic Postgres incident: WAL accumulates in pg_wal, the disk fills, and the database stops accepting writes. It is well documented and entirely avoidable with monitoring — it is also a failure mode that logical dumps simply do not have.
Side by side
| pgBackRest | Backup Data | |
|---|---|---|
| Backup type | Physical + WAL | Logical dumps |
| RPO | Seconds | Your dump interval |
| PITR to a transaction | Yes | No |
| Cross-version restore | No | Yes |
| Works on managed Postgres | Usually not | Yes |
| Non-Postgres data in the same system | No | Yes — files, other engines |
| Deduplication | Page-level incrementals | Content-defined chunking across everything |
| Encryption | Yes, repo-level | Yes, client-side AES-256-GCM |
| Repository | You host it | Managed |
| Config changes to Postgres | Required | None |
| Cost | Free + your infrastructure + your time | Free to 5 GB, then from $12/mo |
Which one, honestly
Use pgBackRest if you self-host Postgres, you need an RPO measured in seconds, your database is large enough that logical restore time is a real problem, and you have someone who will own the repository and monitor archive_command. For a serious self-hosted Postgres shop, it is the right answer and nothing here beats it.
Use logical dumps if you are on managed Postgres and cannot configure WAL archiving, you want backups portable across versions and providers, you back up more than just Postgres, or an RPO of hours is genuinely fine for your data — which, for most application databases, it is.
Use both if the database matters enough to warrant it. They cover different failures and the combination is stronger than either:
pgBackRest → repo in your cloud account → PITR to the second, fast large restores
Logical dump → off-provider snapshots → survives account loss, restores anywhere
That is not hedging. Physical backups give you granularity; logical backups give you portability and independence. The failure modes they cover barely overlap.
Running the second half
If you already have pgBackRest, adding an independent logical copy is a nightly dump and an upload:
pg_dump --format=custom --no-owner \
--file=./db-dumps/app.dump \
"postgresql://postgres@localhost:5432/app_db"
import { BackupClient } from "@lighthouse-web3/baas-js-sdk";
const client = new BackupClient({
apiKey: process.env.LH_API_KEY, // write + read scopes only
workspaceId: process.env.LH_WORKSPACE_ID,
});
const snapshot = await client.backup(["./db-dumps"], {
description: "nightly logical dump",
tags: { type: "db-backup", engine: "postgres", env: "prod" },
encryption: {
keyfilePath: "/secure/lh.keyfile",
passphrase: process.env.LH_KEYFILE_PASSPHRASE,
},
});
Keep the dump filename stable — overwrite app.dump each run — so content-defined chunking ships only the delta. You hold the encryption keys; lose the keyfile and passphrase and the data is unrecoverable, with no server-side reset.
Run the dump from a replica if the extra read load on the primary is a concern. And drill both restore paths, not just the fast one — see the Postgres guide and how to test your backups.
Start with the free tier: backupdata.io has 5 GB free, no card, and the 10-minute quickstart gets you to a first verified snapshot today.