pg-bkup is configured with environment variables, CLI flags and an optional YAML file. For every setting the order is: flag (when given) > variable > deprecated name > config file > default. Every secret also accepts <NAME>_FILE (Docker and Kubernetes secrets). pg-bkup config prints the resolved configuration with its sources (secrets redacted).
Upgrading from 1.x? All 1.x variables and flags still work. See Upgrading to v2 for the behaviour changes.
Commands
Command
Description
backup
Back up now, or as a daemon with --cron-expression.
restore -f FILE
Stream a backup back into -d DB (.sql, .sql.gz, .sql.zst, .dump, optionally .gpg/.age).
migrate
Copy DB_* into TARGET_DB_* with pg_dump \| psql, no file.
verify -f FILE
Download, decrypt and decompress a backup and check its sha256.
list
Backup history from the index (--json, --all, --storage-scan).
delete -f FILE
Delete a backup, its sidecar and its index entry.
prune
Apply the retention policy (--dry-run).
reconcile
Rebuild the index from the storage (--from-index OLD after a rename).
config
Show the resolved configuration; --env-docs prints the table below.
health
Docker HEALTHCHECK for daemon mode.
version
Print the version.
The image also has backup, restore and migrate wrapper scripts and the bkup alias.
The image contains the PostgreSQL 16, 17 and 18 clients (/usr/libexec/postgresqlNN/). For each server pg-bkup reads server_version_num and runs the lowest pg_dump that is not older than the server (servers 9.2 to 16 use pg_dump 16), so dumps can be replayed on the same server version. Restores use the newest psql/pg_restore. PG_CLIENT_VERSION forces a major.
Connection settings reach the clients through their environment (PGHOST, PGPORT, PGUSER, PGPASSWORD, PGSSLMODE, PGSSLROOTCERT, PGSSLCERT, PGSSLKEY), never through the command line.
Restore behaviour
Backup
Restored with
plain dump of one database
psql -v ON_ERROR_STOP=1 --single-transaction -d DB
custom format (PGDMP header, .dump)
pg_restore --no-owner -f - piped into the same psql
--all-in-one (pg_dumpall)
psql -d DB_AUTH_DATABASE (or -d), no transaction, no ON_ERROR_STOP
The format is detected from the first bytes of the decompressed stream. A failing download, decryption or decompression kills the client before it sees the end of its input, so nothing is committed. RESTORE_SINGLE_TRANSACTION, RESTORE_ON_ERROR_STOP and RESTORE_NO_OWNER change these defaults.
A dump names the roles of the server it was taken on and sets the parameters of the pg_dump that wrote it. So that a restore on another server (other roles, older version) does not stop at those, database dumps and migrations are adjusted on the way to psql:
ALTER ... OWNER TO is skipped (RESTORE_NO_OWNER, default on): the restoring user owns the objects.
GRANT, REVOKE and ALTER DEFAULT PRIVILEGES (and OWNER TO with RESTORE_NO_OWNER=false) are kept, but a role missing on the server, or a missing right, skips the statement with a warning instead of failing the restore.
SET of a parameter the server may not know (transaction_timeout from pg_dump 17+) is skipped with a warning on older servers.
A pg_dump --create dump is restored into the database the restore names: its DROP/CREATE/ALTER DATABASE statements, the comment and grants on that database, and its \connect are skipped, never applied to the source database.
Any other error still stops the restore and rolls it back. --all-in-one dumps are replayed as they are: they create the roles they name.
Posta base URL (https://posta.example.com) for email notifications through Posta
POSTA_API_KEY
POSTA_API_KEY_FILE
Posta API key with the send scope
POSTA_WORKSPACE_ID
Posta workspace id (only for account-wide API keys)
POSTA_FROM
Posta sender address (default MAIL_FROM)
POSTA_TO
Posta recipients, comma separated (default MAIL_TO)
POSTA_TEMPLATE
Posta template name for notifications; the event fields are passed as template data (default: built-in HTML)
POSTA_TEMPLATE_ERROR
Posta template name for failures (default POSTA_TEMPLATE)
POSTA_LANGUAGE
Posta template language
WEBHOOK_URL
Generic JSON webhook URL
WEBHOOK_SECRET
WEBHOOK_SECRET_FILE
HMAC-SHA256 secret for the X-Bkup-Signature header
SLACK_WEBHOOK_URL
SLACK_WEBHOOK_URL_FILE
Slack incoming webhook URL
DISCORD_WEBHOOK_URL
DISCORD_WEBHOOK_URL_FILE
Discord webhook URL
NTFY_URL
ntfy topic URL
NTFY_TOKEN
NTFY_TOKEN_FILE
ntfy access token
NOTIFY_ON
always
When to notify (always, failure, success, never)
HEALTHCHECK_PING_URL
healthchecks.io-style URL pinged on start (/start), success and failure (/fail)
BACKUP_REFERENCE
Free text included in notifications
TEMPLATES_DIR
/config/templates
Directory with custom notification templates
database
Variable
Flag
Default
Fallbacks
Description
DB_URL
DB_URL_FILE
Connection URL: postgres://user:pass@host:5432/db?sslmode=require or jdbc:postgresql://host:5432/db?user=u&password=p (overrides host, port, user, password; its database is used when DB_NAME is not set)
DB_HOST
localhost
Database host
DB_PORT
5432
Database port
DB_NAME
--dbname-d
Database name
DB_USER
DB_USERNAME
Database user
DB_PASSWORD
DB_PASSWORD_FILE
Database password
DB_SSL_MODE
libpq sslmode, passed to pg_dump, psql and pg_restore as PGSSLMODE (empty = libpq default, prefer) (disable, allow, prefer, require, verify-ca, verify-full)
DB_SSL_CA
CA certificate file (PGSSLROOTCERT)
DB_SSL_CERT
Client certificate file (PGSSLCERT)
DB_SSL_KEY
Client key file (PGSSLKEY)
BACKUP_ALL_DATABASES
--all-databases-a
backup: every database (templates and ‘postgres’ excluded), one file each; migrate: every database into the same name on the target
BACKUP_ALL_IN_ONE
--all-in-one-A
Back up the whole instance (roles, tablespaces, all databases) into one file with pg_dumpall
BACKUP_EXCLUDE_DATABASES
--exclude-db
Databases to skip with –all-databases / –all-in-one, comma separated (repeatable flag)
TARGET_DB_URL
TARGET_DB_URL_FILE
migrate: target connection URL (postgres:// or jdbc:postgresql://)
Maintenance database used to list databases, create databases and run pg_dumpall
TARGET_DB_AUTH_DATABASE
postgres
migrate: target maintenance database
TARGET_DB_SSL_CERT
migrate: target client certificate file
TARGET_DB_SSL_KEY
migrate: target client key file
PG_DUMP_FORMAT
--dump-format
plain
Dump format: plain (.sql, psql) or custom (.dump, pg_dump -Fc -Z0, pg_restore); COMPRESSION applies to both (plain, custom)
PG_CLIENT_VERSION
Force a PostgreSQL client major (16, 17, 18); default: the lowest bundled client >= the server version
BACKUP_SCHEMA_ONLY
--schema-only
Dump the schema only (file name infix schema)
BACKUP_DATA_ONLY
--data-only
Dump the data only (file name infix data)
BACKUP_TABLES
--tables-t
Only these tables (pg_dump -t patterns), comma separated or repeated (file name infix tables_N)
BACKUP_EXCLUDE_TABLES
--exclude-table
Skip these tables (pg_dump –exclude-table patterns), comma separated or repeated
BACKUP_NO_ROLE_PASSWORDS
--no-role-passwords
–all-in-one / migrate –entire-instance: do not dump role passwords (managed services such as Aiven, OVH)
MIGRATE_ENTIRE_INSTANCE
--entire-instance-I
migrate: copy the whole instance (roles, tablespaces, all databases) with pg_dumpall
RESTORE_SINGLE_TRANSACTION
true
Restore a database dump in one transaction (all or nothing); not used for –all-in-one dumps
RESTORE_ON_ERROR_STOP
auto
Stop a psql restore at the first error; auto = on for database dumps, off for –all-in-one (pg_dumpall) dumps, which always contain ‘role already exists’ errors (auto, true, false)
PG_CLEAN
true
Drop objects before recreating them (pg_dump/pg_restore –clean –if-exists), so a restore replaces an existing database inside its transaction
RESTORE_NO_OWNER
true
Do not restore object ownership: skip ALTER … OWNER TO (pg_restore –no-owner for custom dumps), so the restoring user owns the objects; grants to roles missing on the server are skipped with a warning either way
Scheduled Backups
Running in Scheduled Mode
Docker: Use the --cron-expression flag or the BACKUP_CRON_EXPRESSION environment variable to schedule backups.
Kubernetes: Use a CronJob resource for scheduled backups.
Cron Syntax
The cron syntax consists of five fields:
* * * * * command
Field
Description
Values
Minute
Minute of the hour
0-59
Hour
Hour of the day
0-23
Day of Month
Day of the month
1-31
Month
Month of the year
1-12
Day of Week
Day of the week (0 = Sunday)
0-7
Examples
Every 30 minutes: */30 * * * *
Every hour at minute 0: 0 * * * *
Every day at 1:00 AM: 0 1 * * *
Predefined Schedules
Entry
Description
Equivalent To
@yearly (or @annually)
Run once a year, midnight, Jan. 1st
0 0 1 1 *
@monthly
Run once a month, midnight, first of month
0 0 1 * *
@weekly
Run once a week, midnight between Sat/Sun
0 0 * * 0
@daily (or @midnight)
Run once a day, midnight
0 0 * * *
@hourly
Run once an hour, beginning of hour
0 * * * *
Intervals
You can also schedule backups at fixed intervals using the format:
@every <duration>
Example: @every 1h30m10s runs the backup every 1 hour, 30 minutes, and 10 seconds.
v2 also accepts 6-field expressions (with seconds). In daemon mode a failed run is logged and notified, and the daemon keeps running; BACKUP_RUN_ON_START=true runs one backup at start.