SKIP LOCKED: Building a Job Queue in Plain Postgres
PostgreSQL's `SELECT ... FOR UPDATE SKIP LOCKED` clause lets multiple workers concurrently pull non-overlapping rows from a queue table without contention, turning a regular table into a reliable job queue without Redis or RabbitMQ.
SKIP LOCKED is a clause added to PostgreSQL in version 9.5 (2016) that changes how `SELECT ... FOR UPDATE` behaves when a row is already locked by another transaction. Without it, the second transaction blocks waiting for the lock. With it, the locked row is simply skipped and the query returns the next available row. This tiny semantic change is enough to build a job queue on a plain PostgreSQL table. A worker runs something like `SELECT * FROM jobs WHERE status = 'available' ORDER BY scheduled_at LIMIT 1 FOR UPDATE SKIP LOCKED`, marks the row as in-flight, processes the job, and on success deletes or marks it complete. Multiple workers running this query in parallel will each pick up different rows without coordinating through any external broker. The pattern is the foundation of Elixir's Oban job library, and similar implementations exist in Python (procrastinate), Ruby (Que), and Go. Realistic throughput is on the order of 1,000 to 10,000 jobs per second per worker, which is enough for the vast majority of background-work needs in typical web applications. Where it loses to dedicated brokers: Redis can sustain 100,000+ operations per second from a single instance with sub-millisecond latency, and RabbitMQ or Kafka scale to millions of messages per second across a cluster with durable retention semantics that a Postgres table is not designed to mimic. What you gain by sticking with Postgres: transactional enqueue (a job and the database changes that produced it commit atomically), trivial inspection (`SELECT * FROM jobs WHERE status = 'failed'`), one backup strategy, no separate operational system to monitor, and the ability to join the queue table against business data. For most internal back-office and small-to-mid SaaS workloads these benefits outweigh the raw throughput ceiling.