systems · postgres

What SKIP LOCKED actually does

2026-06-212 min readsystems

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

dequeue.sql
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.

The mental model

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.

🦀
Ferris' hot tip

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.

Comments
Loading comments…