Yashveer Singh
Connect
<- All posts
SaaS Architecture and Scaling12 min read

Background Job Queues: The Architecture Decision Founders Skip

A background job queue is the system that runs work asynchronously from the user request. It is the right place for sending email, processing files, calling external APIs, generating reports, and anything that should not block the response. The queue choice determines the failure model, the retry semantics, the observability story, and the operational tax of the product for years. Most founders pick by accident. The ones who pick by design save quarters of work.

Written by Yashveer Singh, founder of Yashveer Labs.

What you actually need to know

  • Almost every SaaS needs a background queue from day one.
  • Postgres backed queues are the right starting point for most teams.
  • Move to Redis based or dedicated queues when scale demands.
  • Workflow engines are a different tool for multi step processes.
  • Idempotency, retries, and dead letter handling are non negotiable.
Queue optionBest fitScale ceilingOperational tax
Postgres queue (Graphile, River, pg-boss)Most early SaaS5k to 10k jobs per minuteNegligible
Redis queue (BullMQ, Sidekiq)Growing SaaS50k to 100k jobs per minuteLow
SQS or RabbitMQHigh scale or specific routing needsHundreds of thousands per minuteMedium
Inngest, Trigger.devTeams that want managedVendor scalesLowest
Temporal, Step FunctionsMulti step workflowsHighHigher operational overhead

The core argument

Every SaaS I have rescued had a queue problem. The pattern is consistent. The team did not pick a queue. They picked the first thing that worked. The first thing that worked was usually a setTimeout, a hand rolled cron, or a Sidekiq install with no monitoring. The product worked at small scale. At meaningful scale, the queue became the source of incidents.

The right queue is the one that matches the workload, the team size, and the operational appetite. A team of two engineers should not be running Kafka for background jobs. A team of fifty engineers should not be running a single Postgres table. The choice changes as the product grows.

The mistake is treating the queue as a low value decision. The queue is one of the three or four architectural choices that compound. Get it right and the product grows quietly. Get it wrong and the team spends a year unwinding the choice while the product stalls.

The good news is that the modern landscape has good defaults. For most early stage SaaS, a Postgres backed queue is the right call. The operational tax is near zero. The scale is sufficient for the first few thousand customers. The migration path to something heavier is well understood.

Picking the right queue for the workload

Three workload shapes. Steady state low volume. Bursty high volume. Long running stateful.

Steady state low volume is the easy case. A few hundred jobs per minute, predictable. Almost any queue works. Pick the one that integrates cleanly with your stack.

Bursty high volume is where the queue choice matters. The queue has to absorb the burst without dropping jobs and process them as fast as the worker pool allows. Redis based queues handle this well. Postgres based queues hit limits earlier.

Long running stateful is the workflow engine case. A job that runs across multiple steps over hours or days, with retries per step and the ability to resume after a worker restart. Temporal, Inngest, and Step Functions are the right tools. A simple queue is the wrong tool.

How much does this cost

OptionEngineering setupMonthly cost at modest scaleNotes
Postgres queueA few hoursNegligibleRuns on your existing database
Redis queueHalf a day50 to 200 USD for RedisAdd Redis to the stack
SQSHalf a dayUnder 50 USDAWS specific
InngestHalf a dayFree to 200 USDManaged
Trigger.devHalf a dayFree to 200 USDManaged
Temporal CloudOne to two daysHigherWorkflow engine

Features the queue must have

  • Idempotent job design as a first class concern.
  • Exponential backoff with maximum retry count.
  • Dead letter destination for terminal failures.
  • Observability for queue depth, throughput, failure rate, and latency.
  • Schedule support for cron style jobs.
  • Worker concurrency control to prevent resource exhaustion.
  • A clear path from development to production.

Expert opinion

The queue is the part of the system that runs in the dark. It does not have a UI. It does not have a request log. It does not surface its failures unless you wire them up. The teams that take the queue seriously from day one get a quiet, reliable layer. The teams that treat it as an afterthought get the loudest incidents of their year.

>

Yashveer Singh, founder of Yashveer Labs

How this played out on a real project

A SaaS client had been running their background work on a hand rolled cron loop that processed a database table. The system worked for the first three thousand customers. At seven thousand customers the cron loop was missing windows and producing duplicate work. The team had spent six weeks trying to patch it.

We migrated to a Postgres backed queue with idempotent jobs and exponential backoff retries. The migration took eight working days. The queue depth dropped from a backlog of hundreds of thousands of stuck jobs to a steady state of under a thousand. The duplicate work stopped.

Eighteen months later, at thirty thousand customers, we migrated the highest volume job class to a Redis queue. The migration was contained because the abstraction over the queue had been built correctly the first time. The team did not have to rewrite job logic.

For more on the related architecture work, see the outbox pattern a SaaS reliability cheat code and async job failure recovery patterns that actually work.

Common mistakes teams make

  1. No queue at all. Long running work in the request thread.
  2. Hand rolled cron loops over a database table.
  3. Jobs that are not idempotent. Retries duplicate side effects.
  4. No dead letter handling. Failed jobs disappear into the void.
  5. No observability. The queue is a black box.
  6. Mixing job priorities in one queue. A low priority job blocks a high priority one.
  7. Treating the queue as the workflow engine. Multi step state belongs elsewhere.
  8. Picking Kafka for background jobs. Wrong tool for the workload.

A two week plan to put a queue in place

  1. Day one. Inventory the candidate background work. Email, webhooks, exports, scheduled tasks.
  2. Days two and three. Pick the queue. Postgres backed for most early SaaS.
  3. Days four to six. Migrate the first job. Send the welcome email through the queue.
  4. Days seven to nine. Migrate the rest. Make every job idempotent.
  5. Day ten. Wire observability. Queue depth, throughput, failure rate.
  6. Days eleven and twelve. Set up alerts. Define the runbook.
  7. Days thirteen and fourteen. Load test. Confirm the queue handles the expected burst.

For more on the related infrastructure work, read background jobs at scale Inngest Trigger Cron and beyond and workflow engines when you need Temporal when you need Cron. On the reliability side, why your SaaS should have a job queue from day one is the natural next read.

FAQ

Frequently asked

Author

The engineer behind this page

This was written by Yashveer Singh. Full stack developer, founder of Yashveer Labs, currently in Class 12 in New Delhi, shipping production systems while most of my peers are still writing their first console app. I am pointing the work, on purpose, at machine learning, AI engineering, and cybersecurity. If you are reading this because you want to hire someone who will not waste your time or your money, that is the role I am built for.

Related reading