Comparison
Orch8 vs BullMQ
BullMQ is an excellent job queue — fast, simple, and battle-tested for background task processing. Orch8 is a workflow orchestration engine for multi-step sequences that need crash recovery, branching, and time-aware scheduling. They solve fundamentally different problems.
Job queue vs workflow engine
A job queue processes individual tasks. A workflow engine orchestrates multi-step sequences with state, branching, and recovery. Many teams start with BullMQ and add Orch8 when their workflows grow beyond what a job queue was designed for.
BullMQ excels at
- ✓Fast background job processing with Redis
- ✓Simple one-off tasks: resize image, send email, process payment
- ✓Priority queues and FIFO ordering
- ✓Job scheduling with cron and repeat
- ✓Rate limiting per queue
- ✓Minimal setup — Redis + npm package
Orch8 adds on top
- ✓Multi-step sequences with state between steps
- ✓Crash recovery — resume from last completed step
- ✓Conditional branching, loops, and parallel execution
- ✓Persisted step receipts, plus explicit idempotency for external effects
- ✓Delays from minutes to months with timezone + business-day support
- ✓Human-in-the-loop approval gates
Side-by-side comparison
| Dimension | Orch8 | BullMQ |
|---|---|---|
| Type | Workflow orchestration engine | Job queue |
| Language | Rust engine | TypeScript and Python clients |
| Storage | PostgreSQL or SQLite | Redis |
| Recovery | Resume persisted sequence state | Retry failed or stalled jobs |
| Multi-step sequences | Native block DSL | Parent-child flows and application code |
| Branching logic | Router blocks with conditions | Custom code between jobs |
| Rate limiting | Per-resource with sliding window, defer-not-drop | Per-queue with token bucket |
| Timezone scheduling | Built-in, per-task IANA timezone | Not built-in |
| Business-day awareness | Built-in | Not built-in |
| Human-in-the-loop | Native — wait_for_signal | Not built-in |
| AI agent support | Loop + Router + LLM rate limiting | Not built-in |
| Worker model | REST long-poll (any language) | BullMQ worker clients |
| License | BUSL-1.1 | MIT |
Signs you've outgrown a job queue
BullMQ is the right tool for many workloads. These are the signals that your workload has evolved into something that needs orchestration.
You're chaining jobs with custom glue code
Job A finishes → you create Job B with Job A's output → Job B finishes → you create Job C. This is a workflow. BullMQ gives you the pieces. Orch8 gives you the glue.
You're building a state machine for sequence position
Tracking which step a user is on, what's been sent, what's pending — this is workflow state. If you're storing it in Redis or your database manually, you're building a workflow engine.
Crashes cause duplicate side effects
A provider can accept an effect before either system records completion. Orch8 persists committed step receipts, but both systems still require provider idempotency and reconciliation for unknown outcomes.
You need conditional branching mid-sequence
"If the user opened the email, send follow-up A. Otherwise, send follow-up B in 48 hours." This is orchestration logic that BullMQ leaves entirely to you.
You need delays longer than a few minutes
BullMQ delays are Redis-based. Scheduling a job for 14 days from now works, but timezone awareness, business-day exclusion, and DST handling require custom code.
You need language-agnostic HTTP workers
BullMQ documents TypeScript and Python clients. Orch8's worker protocol is plain HTTP, which can also be implemented directly from other languages.
Multi-step sequence: BullMQ vs Orch8
An onboarding drip: send welcome email → wait 3 days → check if user activated → branch based on result.
BullMQ — manual job chaining
// Job 1: Send welcome email
queue.add('send-welcome', { userId });
// In the processor:
worker.on('completed', async (job) => {
if (job.name === 'send-welcome') {
// Schedule next job with delay
await queue.add('check-activation',
{ userId: job.data.userId },
{ delay: 3 * 24 * 60 * 60 * 1000 } // 3 days in ms
);
}
if (job.name === 'check-activation') {
const activated = await checkActivation(
job.data.userId
);
if (activated) {
await queue.add('send-pro-tips', job.data);
} else {
await queue.add('send-nudge', job.data);
}
}
});
// + error handling, dedup, state tracking...Orch8 — declarative sequence
{
"id": "onboarding_drip",
"blocks": [
{
"type": "step",
"handler": "send_welcome"
},
{
"type": "step",
"handler": "check_activation",
"delay": { "days": 3 }
},
{
"type": "router",
"routes": [
{
"condition": "{{outputs.check_activation.activated}}",
"blocks": [
{ "type": "step", "handler": "send_pro_tips" }
]
},
{
"default": true,
"blocks": [
{ "type": "step", "handler": "send_nudge" }
]
}
]
}
]
}
// Crash recovery, dedup, state: handled.When to use which
One-off background tasks (resize image, send single email, process webhook)
BullMQBullMQ is fast, simple, and purpose-built for individual job processing. No need for a workflow engine when there's no sequence.
Multi-step sequences with delays and branching
Orch8Sequences are Orch8's core design. Delays, conditions, branching, loops, and crash recovery are built in — not bolted on.
Simple retry logic for failed operations
BullMQBullMQ has excellent built-in retry with backoff. If your jobs are independent and don't need cross-job state, BullMQ handles retries well.
Retries that must prevent duplicate side effects
Orch8Orch8 persists committed step receipts. Both systems still require idempotent handlers and reconciliation when an external effect has an unknown outcome.
High-throughput independent job processing
BullMQRedis-backed with minimal overhead. BullMQ is optimized for throughput on independent jobs.
Long-running workflows (days to weeks)
Orch8Snapshot-based persistence. Workflows run for weeks without accumulating state overhead. Deploy without killing in-progress workflows.
Workers in Python, Go, or other languages
Orch8BullMQ documents TypeScript and Python clients. Orch8's worker protocol is plain HTTP, so other languages can implement it directly.
They work well together. Use BullMQ for high-throughput independent jobs (image processing, webhook delivery). Use Orch8 for multi-step sequences where state, branching, and crash recovery matter. Many teams run both.