Why add another dependency when PostgreSQL can be your queue?
This project demonstrates how ridiculously simple it is to build a production-ready work queue using just PostgreSQL.
No Redis, no RabbitMQ, no SQS—just Postgres.
Because simplicity is underrated.
You don't need to introduce more moving parts into your architecture when your database can handle it all.
SELECT * FROM tasks
WHERE status = 'pending'
ORDER BY created_at
FOR UPDATE SKIP LOCKED
LIMIT 1That's it. FOR UPDATE SKIP LOCKED ensures multiple workers can safely process tasks concurrently without stepping on each other's toes.
It's basic, reliable, and leverages PostgreSQL's robust ACID guarantees.
It's already in your stack, battle-tested, you just have to use it.
CREATE TABLE tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
payload JSONB NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
picked_at TIMESTAMP,
executed_at TIMESTAMP
);Continuously adds tasks to the queue.
Workers that process tasks in parallel—all safely thanks to PostgreSQL's locking mechanism.
# Start PostgreSQL
docker compose up -d
# Run migrations
npm run migrate
# Let's the party begin
npm run startWatch as multiple workers process different tasks simultaneously without any race conditions. Each producer is able to fetch one task at a time, process it, and mark it as done. A task is never processed more than once. A task is never assigned to more than one worker at a time.
You don't always need specialized queue infrastructure. PostgreSQL is:
- Simple - Already in your stack
- Reliable - Battle-tested ACID guarantees
- Performant - Handles thousands of jobs/second
- Cost-effective - No additional services to pay for
and hey, you don't need to consume a "message" to see its payload! :D (just query the tasks table directly!)
- You need millions of messages per second
- You need pub/sub patterns across many many...many services
- You need delayed/scheduled jobs at scale
But for 80% of use cases? Just use Postgres.
- PostgreSQL (with
SKIP LOCKED) - Node.js + TypeScript
- Knex.js (query builder)
- Docker Compose
The best queue is the one you don't have to add. 🚀
