← All posts

Why BullMQ beat in-API file conversion

Sync conversion in HTTP vs a Redis queue: p95 dropped from 800ms to 3.8ms, throughput rose 4.8×—plus the complexity trade-off.

Contents

In brief

A file conversion and sharing app initially did all work inside the HTTP request. As files grew, users waited hundreds of milliseconds where an immediate acknowledgment would suffice. The author moved heavy processing to BullMQ and Redis and measured gains in latency and throughput.

What happened

The first version was straightforward: upload → convert in the same process that serves the API → return the result. Small files were fine. At scale, connections stayed open while the server burned CPU and disk—even though the client only needed “accepted for processing.”

The new flow: upload → BullMQ job → instant API response → worker converts → status update → user gets the file. Redis holds the queue; workers scale via concurrency; retries and failure handling are built into the queue model.

Load testing with 20 concurrent requests showed API p95 latency falling roughly 212× (800ms → 3.8ms). Throughput rose 4.8× (1.3 → 6.2 requests/sec). Conversion itself did not get faster—the architecture changed by taking heavy work off the request path.

Why it matters

Sync processing in the API feels simpler at low load. Any long I/O or CPU in a request handler hits timeouts, connection pools, and UX. “Accept fast, process elsewhere” is the baseline for files, video, reports, and mailers.

Async has a real cost: Redis, worker processes, queue monitoring, and eventual consistency—users do not get the file in the same response as the upload. If the business requires an instant result in one round-trip, sync may still be justified. For convert-and-share apps, that is uncommon.

In practice

  1. Separate file intake from heavy processing—the API returns a jobId and status.
  2. Pick a queue with retries and dead-letter handling (BullMQ on Redis is a common Node.js choice).
  3. Scale workers, not only API replicas—CPU-bound work lives there.
  4. Give clients polling, webhooks, or SSE for “ready” status.
  5. Measure API p95/p99 separately from full job completion time.
  6. Document the trade-off: simpler code vs infrastructure and time-to-result.

Takeaway

The Dev.to story is a short, numbers-backed reminder: wins often come not from “faster functions” but from moving work out of the HTTP request. BullMQ + Redis paid off for this file service; your threshold may differ, but the pattern is universal.