Tidebase Tidebase GitHub Start self-hosting
Docs · Comparisons

Tidebase vs BullMQ

The short answer: BullMQ retries jobs; Tidebase resumes them. A BullMQ retry re-runs the whole job function from the top — anything it already did, it does again. A Tidebase re-invocation replays completed steps from Postgres and continues from the first incomplete one. If your jobs are short and idempotent, BullMQ is enough; if a job is twenty minutes of LLM calls and external writes, the difference is the product.

Tidebase is an open-source checkpoint layer for AI agents: wrap your steps, and failed runs resume from the last safe point — in your own Postgres, without moving execution into a new runtime.

The structural difference

BullMQ is a queue. Redis-backed, fast, mature: producers add jobs, workers process them, failures retry with backoff. The job function is opaque to BullMQ — it knows that the job failed, never where. State inside a job attempt lives and dies with the process.

Tidebase is a checkpoint layer with a queue attached. The unit of durability is the step, not the job. run.step('fetch-sources', ...) writes its result to Postgres; when the run is re-invoked — by Tidebase’s own queue, a recovery webhook, or your retry button — finished steps return their stored results and the twenty minutes of completed LLM work is never re-bought. External writes carry an explicit replay contract: a failed step with undeclared side effects parks for manual review instead of blindly re-firing.

Side by side

TidebaseBullMQ
Backing storePostgresRedis
Failure granularityStep — resume from last checkpointJob — retry re-runs everything
Double-fire protectionInput-hashed checkpoints, idempotency keys, manual_review classificationYour job code’s responsibility
Run record for product UIsLive state, events, step results, SSEJob status/progress fields
Human approval gatesBuilt in, durable, exactly-onceNot a queue concern
Per-run LLM cost ledgerBuilt inNot a queue concern
Throughput as a queueModest (Postgres, agent-workflow-shaped)Excellent (Redis, battle-tested at scale)
Delayed/repeatable jobsDelays, cron schedules, dedupeMature support
MaturitySelf-hosted alpha, opt-in authProduction standard for Node queues

Choose BullMQ if

  • Jobs are short, cheap to re-run, or naturally idempotent — thumbnails, emails, cache warming. A checkpoint layer adds nothing there.
  • You need raw queue throughput and the Redis operational model you already have.

Choose Tidebase if

  • A retried job re-doing its finished work is expensive (LLM tokens, rate-limited APIs) or dangerous (payments, sends, deploys).
  • You want the run visible — progress, pending approvals, what each step returned, what it cost — as Postgres rows your product can query.
  • You’d rather not hand-roll the status column, the “did step 7 fire?” forensics, and the idempotency bookkeeping around a queue.

They also compose: plenty of stacks keep BullMQ for dispatch and wrap the job body in tide.run(...) for checkpoints — the queue decides when, Tidebase remembers what. The honest tradeoff either way: Tidebase never executes your code, so something — BullMQ, Tidebase’s own queues, or your infra — must invoke it.

Repo: https://github.com/BlueprintLabIO/tidebase · See also: Tidebase vs Inngest