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.
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 option
Best fit
Scale ceiling
Operational tax
Postgres queue (Graphile, River, pg-boss)
Most early SaaS
5k to 10k jobs per minute
Negligible
Redis queue (BullMQ, Sidekiq)
Growing SaaS
50k to 100k jobs per minute
Low
SQS or RabbitMQ
High scale or specific routing needs
Hundreds of thousands per minute
Medium
Inngest, Trigger.dev
Teams that want managed
Vendor scales
Lowest
Temporal, Step Functions
Multi step workflows
High
Higher 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
Option
Engineering setup
Monthly cost at modest scale
Notes
Postgres queue
A few hours
Negligible
Runs on your existing database
Redis queue
Half a day
50 to 200 USD for Redis
Add Redis to the stack
SQS
Half a day
Under 50 USD
AWS specific
Inngest
Half a day
Free to 200 USD
Managed
Trigger.dev
Half a day
Free to 200 USD
Managed
Temporal Cloud
One to two days
Higher
Workflow 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
- No queue at all. Long running work in the request thread.
- Hand rolled cron loops over a database table.
- Jobs that are not idempotent. Retries duplicate side effects.
- No dead letter handling. Failed jobs disappear into the void.
- No observability. The queue is a black box.
- Mixing job priorities in one queue. A low priority job blocks a high priority one.
- Treating the queue as the workflow engine. Multi step state belongs elsewhere.
- Picking Kafka for background jobs. Wrong tool for the workload.
A two week plan to put a queue in place
- Day one. Inventory the candidate background work. Email, webhooks, exports, scheduled tasks.
- Days two and three. Pick the queue. Postgres backed for most early SaaS.
- Days four to six. Migrate the first job. Send the welcome email through the queue.
- Days seven to nine. Migrate the rest. Make every job idempotent.
- Day ten. Wire observability. Queue depth, throughput, failure rate.
- Days eleven and twelve. Set up alerts. Define the runbook.
- 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
- When do I need a background job queue?
- What is the simplest queue I can start with?
- When should I move off Postgres for queues?
- What is the difference between a queue and a workflow engine?
- How do I handle retries?
- What about scheduled jobs?
- How do I monitor a queue?
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 for paying clients while still in school. 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.