What SKIP LOCKED actually does
You don't always need Kafka. For a lot of workloads, Postgres is the queue — and
SKIP LOCKED is the one keyword that makes it work under concurrency.
The whole queue
1UPDATE jobs SET status = 'claimed'2WHERE id = (3 SELECT id FROM jobs WHERE status = 'pending'4 ORDER BY created_at FOR UPDATE SKIP LOCKED LIMIT 15)6RETURNING *;
Why it doesn't block
Without SKIP LOCKED, two workers running this query at once would serialize:
the second blocks on the first's row lock. With it, the second worker skips any
row already locked and grabs the next available one.
FOR UPDATE says "lock these rows." SKIP LOCKED adds "...and ignore the ones
someone else already locked." Together they give you contention-free, concurrent
dequeue with zero coordination.
Pair this with LISTEN/NOTIFY to wake workers on insert instead of polling. Push
for latency, pull (this query) for correctness. That combo is the heart of every
Postgres-native queue — Graphile Worker, River, and NotiQ.
When to reach for a real broker
- Throughput beyond what a single primary can sustain.
- Cross-region replication of the queue itself.
- Fan-out to many independent consumer groups.
Until then, the database you already operate is one SKIP LOCKED away from being
a perfectly good job queue.