Skip to main content

Database Snapshots

EffectStream supports automated database snapshots using pg_dump. Snapshots let you take point-in-time backups of your node's database while it continues syncing — no downtime, no interruption.

How it works

Snapshots are triggered by wall-clock time — once the configured interval (default: 1 hour) has elapsed since the last snapshot, the next processed block triggers a new one.

The runtime spawns pg_dump as a background task using Effection's spawn(), so the sync loop continues processing blocks while the dump runs. A guard flag prevents overlapping dumps — if pg_dump is still running when the next interval elapses, it waits until the current dump finishes.

Because pg_dump uses PostgreSQL's MVCC, it takes a consistent snapshot at the moment the command starts. Normal operations — SELECT, INSERT, UPDATE, DELETE — continue uninterrupted. Only DDL statements (DROP TABLE, ALTER TABLE, TRUNCATE) are briefly blocked.

This feature requires a real PostgreSQL instance — snapshots are skipped when running under PGlite (PGLITE=true), because PGlite's internal catalog schema may not match the locally-installed pg_dump version.

Prerequisites

pg_dump connects to the database using the same connection variables your node already uses. Make sure these are set correctly in your environment:

VariableDescriptionExample
DB_HOSTPostgreSQL hostlocalhost
DB_PORTPostgreSQL port5432
DB_USERPostgreSQL userpostgres
DB_PWPostgreSQL passwordmysecretpassword
DB_NAMEDatabase to snapshoteffectstream

These are the same variables used by the node's database connection — no extra configuration needed. The password is passed to pg_dump via the PGPASSWORD environment variable (the standard libpq mechanism).

Additionally, pg_dump must be installed and on the PATH of the process running the node:

  • Debian/Ubuntu: apt install postgresql-client
  • macOS: brew install libpq

Setup

Add snapshotConfig to your StartConfig. Every field is optional — an empty object {} is enough to get started:

yield* start({
appName: "my-app",
appVersion: "1.0.0",
syncInfo: ...,
// An empty object uses all defaults (every 3600 seconds, ./snapshots directory,
// full tiered retention policy).
snapshotConfig: {},
});

Full configuration

snapshotConfig: {
// Wall-clock seconds between snapshots. Default: 3600 (1 hour)
intervalSeconds: 1800,

// Directory where .dump files are written. Default: "./snapshots"
path: "./backups",

retention: {
// Keep one snapshot per hour for the last 24 hours. Default: true
lastDayHourly: true,
// Keep one snapshot per 6-hour window for the last 3 days. Default: true
last3DaysSixHourly: true,
// Keep one snapshot per day for the last N days. Default: 7
lastNDaysDaily: 14,
},
}

Environment variable overrides

All config fields can also be driven from environment variables:

VariableOverridesDefault
EFFECTSTREAM_SNAPSHOT_INTERVAL_SECONDSintervalSeconds3600 (1 hour)
EFFECTSTREAM_SNAPSHOT_PATHpath./snapshots
EFFECTSTREAM_SNAPSHOT_LAST_DAY_HOURLYretention.lastDayHourlytrue
EFFECTSTREAM_SNAPSHOT_LAST_3_DAYS_SIX_HOURLYretention.last3DaysSixHourlytrue
EFFECTSTREAM_SNAPSHOT_LAST_N_DAYSretention.lastNDaysDaily7

Retention policy

The retention policy is time-based, using each file's modification time (mtime). Three tiers apply automatically:

File ageWhat is kept
≤ 24 hoursOne snapshot per hour
24 hours – 3 daysOne snapshot per 6-hour window
3 days – N daysOne snapshot per day
Older than N daysDeleted

Within each time window the newest file is kept; older files in the same window are deleted.

Setting a tier flag to false disables that tier's pruning — all files in that age range are kept as-is.

Restoring a snapshot

Snapshot files use pg_dump custom format. Use pg_restore to apply them.

Restore into an existing database (drops and recreates all objects):

pg_restore -h localhost -p 5432 -U postgres -d postgres --clean snapshot-2026-04-09T14-30-00Z.dump

List the contents of a dump without restoring:

pg_restore --list snapshot-2026-04-09T14-30-00Z.dump

Restore only a specific table:

pg_restore -h localhost -p 5432 -U postgres -d postgres -t my_table snapshot-2026-04-09T14-30-00Z.dump

File naming

Each snapshot is named with a UTC timestamp:

./snapshots/
snapshot-2026-04-09T10-00-00Z.dump
snapshot-2026-04-09T11-00-00Z.dump
snapshot-2026-04-09T12-00-00Z.dump

The timestamp is for human readability only. The retention policy uses file mtime, not the filename, to determine which files to keep.