Guides / pg_dump vs pg_basebackup vs pgBackRest

pg_dump, pg_basebackup or pgBackRest: which PostgreSQL backup to run

pg_dump writes the SQL to rebuild a database. pg_basebackup copies the cluster's files. pgBackRest manages file copies plus the write-ahead log, which is what makes recovery to any moment possible. They differ in what they restore to, what they need from the server, where they can restore, and how you test them.

pg_dumppg_basebackuppgBackRest
KindLogical: SQL and data, one databasePhysical: the data directory, whole clusterPhysical, with WAL archiving, retention and parallel restore
Restores toThe moment the dump beganThe moment the copy ended, or any later point if you archive WAL yourselfAny moment in the retention window (point-in-time recovery)
Restores onAny platform, the same or a newer major versionThe same major version and architectureThe same major version and architecture
GranularityOne database, schema or table at a timeAll or nothingAll or nothing, to a point in time
NeedsA connection and a role that can readA replication connection and a free WAL sender; file-system access to restoreFile-system access on the server; a repository host or an S3 bucket
Works on managed PostgresYes: Supabase, Neon, RDS, Railway, Render and the restUsually not: no replication connection or file systemNo
Backup sizeCompressed data, no indexes; rebuilt on restoreEverything on disk, indexes includedFull, differential and incremental, so a day's increment is small
Restore speedSlowest: rows are inserted and indexes rebuiltFast: files are copied into placeFast, parallel, plus WAL replay to the target time
Load on the sourceOne snapshot read; no locks that block the applicationA full file read; needs a free WAL senderA full read for a full backup, less for incrementals
Tested byRestoring into a scratch database and counting rowsStarting a server on the copypgbackrest verify for the files; a restore to check the data

pg_dump

pg_dump connects like any client and reads the whole database from one snapshot, so a dump taken while the application writes is consistent as of the moment it started. It takes no locks that block reads or writes. The output is either SQL or an archive pg_restore can load selectively and in parallel. Because it is SQL, it loads into a newer major version, onto another operating system, and into a different provider; it is the only one of the three that works against a managed database you cannot log in to.

What it cannot do is recover to a point between dumps. A dump at 02:00 and a mistake at 14:00 loses twelve hours. It also rebuilds every index on restore, which is where a restore of a large database spends most of its time. And pg_dump writes one database; roles and other cluster-wide objects come from pg_dumpall --globals-only. How to back up a PostgreSQL database has the flags, the role and the restore.

pg_basebackup

pg_basebackup ships with PostgreSQL and copies the data directory over a replication connection, the same mechanism a standby uses. With --wal-method=stream it also captures the WAL written during the copy, so the result starts on its own. Restoring means stopping the server, replacing its data directory with the copy, and starting it, which is fast because nothing is rebuilt, and all or nothing because the files are the cluster.

On its own it is a snapshot, like a dump, only bigger and tied to the version and architecture it came from. It becomes point-in-time recovery when you also archive WAL continuously (archive_command or pg_receivewal) and keep the archive beside the base backups, which is the part people get wrong by hand: a missing WAL segment makes every point after it unreachable. PostgreSQL 17 adds native incremental base backups, which shrink the nightly copy. It is the right tool to seed a standby and a fine one for a cluster you run yourself; it needs the replication privilege and a free WAL sender connection (max_wal_senders).

pgBackRest

pgBackRest is what you run when you want point-in-time recovery without assembling it yourself. It takes full, differential and incremental backups, archives WAL to a repository on another host or in an S3-compatible bucket, keeps as many of each as its retention says, verifies the files it holds, and restores in parallel to any moment in the window. Railway's point-in-time recovery is pgBackRest underneath.

The costs are the ones of any physical backup: it runs on the database server with access to the data directory, so it cannot back up a database where you have only a connection; it restores onto the same major version and architecture; and a restore is the whole cluster. Its verify command checks that the files are intact and the WAL chain is complete, which is not the same as a restore that proves the data is there. Treat a scheduled restore to a scratch server as part of running it.

Which to run

Whichever you pick, until a backup has been restored nobody knows whether it restores. A dump restores into a scratch database with row counts compared to the source; a physical backup restores onto a scratch server that has to start. Schedule either. How to test that a backup restores has the checks, from a checksum to a row-for-row comparison.

How SafeGrd fits

SafeGrd takes the logical backup: the schema with pg_dump and the rows over binary COPY from one snapshot, encrypted on the host and written under Object Lock, with each backup uploading only what changed. It restores the newest one on a schedule into a throwaway database and checks every table's row count against the manifest written at backup time, then signs the result. It does not replace pgBackRest for point-in-time recovery; teams that need PITR run both, and SafeGrd vs pgBackRest says where each stops.