background jobs for an app that already has Postgres, without adding Redis
pg-boss 12.30.0. Jobs live in the same database as your data, so enqueueing is part of the transaction that created the row and cannot disagree with it. It carries schedules, retries with backoff, dead letter queues, and job archiving, and 12.30 added autovacuum monitoring because a busy Postgres that stops vacuuming is the usual way a database-backed queue goes bad.
BullMQ 6.3.4 on Redis handles far higher throughput and has the better dashboard, at the cost of a second datastore that can disagree with Postgres after a crash.
Wins when you push tens of thousands of jobs a minute, or you already run Redis for something else.
Trigger.dev 4.5.16 is a good product and a poor fit here: it is a separate orchestration platform with its own runtime and deployment story, which is a lot of moving parts for "send this email in five minutes".
| severity | versions | symptom and fix |
|---|---|---|
| major | >=12.30.0 | A `xmin_horizon` or `autovacuum_disabled` warning appears on the second maintenance pass after upgrading. Vacuum monitoring is on by default in 12.30.0, so an installation whose horizon was already pinned starts warning right after the upgrade. Find what pins the horizon, an idle-in-transaction backend, a replication slot, a standby with hot_standby_feedback, or a prepared transaction, and release it. Setting `monitorVacuum: false` silences the warning and leaves the queue table bloating. evidence |
| minor | >=12.30.0 | Node logs `[PGBOSS_DEP_FETCH_SORT] DeprecationWarning` for `priority` or `orderByCreatedOn`. Both options are ignored as of 12.30.0 and will be rejected in the next major, because the fetch index now leads with the sort keys. Delete them. If you set `priority: false` to go faster, that was measured roughly 180x slower than the default once the index changed. evidence |
| minor | >=12.30.0 | The first boot after upgrading runs a schema migration and rebuilds the fetch index. Schema 40 adds two nullable columns and replaces `job_i5` with `job_i11`. The new index is built with CREATE INDEX CONCURRENTLY before the old one is dropped, so plan for the extra disk (about 15 MB to 19 MB at 500k jobs) and do not run two boots against the same database at once. evidence |
VERDICT background jobs for an app that already has Postgres, without adding Redis PICK pg-boss 12.30.0: pg-boss 12.30.0. Jobs live in the same database as your data, so enqueueing is part of the transaction that created the row and cannot disagree with it. It carries schedules, retries with backoff, dead letter queues, and job archiving, and 12.30 added autovacuum monitoring because a busy Postgres that stops vacuuming is the usual way a database-backed queue goes bad. ALT BullMQ: BullMQ 6.3.4 on Redis handles far higher throughput and has the better dashboard, at the cost of a second datastore that can disagree with Postgres after a crash.; wins when you push tens of thousands of jobs a minute, or you already run Redis for something else AVOID Trigger.dev: Trigger.dev 4.5.16 is a good product and a poor fit here: it is a separate orchestration platform with its own runtime and deployment story, which is a lot of moving parts for "send this email in five minutes". TRAPS (3) [404c8a9c] major: A `xmin_horizon` or `autovacuum_disabled` warning appears on the second maintenance pass after upgrading. [5f8bebc6] minor: Node logs `[PGBOSS_DEP_FETCH_SORT] DeprecationWarning` for `priority` or `orderByCreatedOn`. [1fc7377f] minor: The first boot after upgrading runs a schema migration and rebuilds the fetch index. VERIFIED 2026-09-08 by wellworn reviewer · recheck 2027-01-06 · sources 4