There is no single best background runtime. There are two, and you need both.
In AACFlow, 16 background tasks run on Trigger.dev v4 and 7 processors run on BullMQ. That decision is not historical drift — it is the result of a year of "let's try the same one for everything" and discovering, twice, that one runtime was wrong for half the workload. The split is intentional.
The Job You're Running Tells You the Runtime
Before any framework debate, the question to answer is: what is this job actually doing?
There are two distinct shapes:
- Long, observable, replayable. A workflow execution that calls 12 LLMs and three APIs over 90 seconds. A knowledge-base ingestion that downloads 4,000 documents, chunks them, embeds them, and stores them over half an hour. A mothership inbox task that polls a 200-message Slack thread, summarizes it, decides what to do next, and recurses. These jobs are expensive, slow, irreplaceable. You need to see them, debug them, and replay them from a specific step.
- Short, throughput-bound, idempotent. A webhook fan-out that delivers one event to seven downstream listeners in 200ms total. A notification delivery to a workspace's 50 users. A single document chunk being embedded and stored. These jobs are cheap, fast, and there are tens of thousands of them per minute.
Trigger.dev v4 was built for the first shape. BullMQ was built for the second. Try to swap them and you lose either the visibility (BullMQ for the first) or the throughput (Trigger.dev for the second).



