gem

Configuration

The initializer

bb install writes this file. Everything in it is optional except a registered store.

# config/initializers/boring_backup.rb
BoringBackup.configure do |config|
  config.sentinel_key  = ENV["BB_SENTINEL_KEY"]
  config.prefix        = "database"
  config.min_size      = 2048
  config.ignore_tables = %w[versions logs]

  config.register(:s3) do |store|
    store.bucket = "db-backups"
    store.region = "eu-central-1"
  end
end

Options

optionenvdefaultwhat it does
prefixBB_PREFIXdatabasefirst path segment of every key written to a store
min_sizeBB_MIN_SIZE2048bytes. A dump smaller than this fails the store instead of being kept, which catches an empty or truncated stream before it becomes your only copy
ignore_tablesBB_IGNORE_TABLESnonetable names whose rows are skipped. A restore still creates them, empty
sentinel_keyBB_SENTINEL_KEYnonethe monitor's ping token. Unset means no reporting
sentinel_hostBB_SENTINEL_HOSTboringbackup.compoint the ping somewhere else for staging or a self-hosted sentinel
reportn/atrueset false to skip notifiers entirely, useful in tests
dump_commandn/asee belowreplace the whole pg_dump invocation

Environment variables are read when the configuration object is built, so a value set in the initializer wins over the matching BB_* variable. BB_IGNORE_TABLES takes a comma-separated list.

Database connection

Each connection setting resolves in this order, first hit wins:

  1. the explicit config.pg_* value
  2. ActiveRecord's current connection config, which is why a Rails app configures nothing here
  3. the standard PGHOST, PGPORT, PGUSER, PGPASSWORD and PGDATABASE variables
config.pg_host     = "db.internal"
config.pg_port     = 5432
config.pg_user     = "backup"
config.pg_password = ENV["BACKUP_DB_PASSWORD"]
config.pg_database = "db_production"

A backup only reads, so a role with SELECT and nothing else is enough. If no database name resolves at all the run fails immediately, rather than dumping something unexpected.

The dump command

By default the gem runs:

pg_dump --format=custom --no-owner [--exclude-table-data=… per ignored table]

--format=custom produces a compressed archive that pg_restore can restore selectively. --no-owner drops ownership statements so the dump restores into a database whose roles differ from production.

Override the array when you need flags the gem does not expose:

config.dump_command = [
  config.pg_env,
  "pg_dump",
  "--format=custom",
  "--no-owner",
  "--schema=public"
]

The first element is the environment hash carrying the PG* variables. Keep it, or the command will not know which database to read.

Where backups land

Keys are built from the prefix, the database name and the UTC time of the run:

database/db_production/2026/07/29-03-00-04-812.dump

Every store receives the same key, so one run produces one identifiable artifact across all destinations. Listing a bucket in lexicographic order lists it in chronological order.

Further reading