Skip to content

Vulkan vs. Job Queues

We owe this category a debt. River, pgmq, graphile-worker, Oban, pg-boss, and Solid Queue spent years proving the thesis Vulkan is built on: Postgres is a great place for messages. SKIP LOCKED claiming, transactional enqueue, partial indexes on ready rows — these are the community’s hard-won patterns, and Vulkan uses all of them.

The difference is scope. A job queue answers one question: “run this work, reliably, soon.” Vulkan answers that one and the questions that historically forced you to add Kafka and RabbitMQ next year: what happened? (retention), who else needs to know? (fan-out, routing), can we reprocess? (replay).

pgmqRiverVulkan
At-least-once delivery, SKIP LOCKED
Transactional enqueue
Retries with backoff, scheduling❌ basic visibility timeout
Dead lettersarchive table✅ per consumer group
Retained, replayable event log
Multiple independent consumer groups per message
Routing bindings
Per-key FIFO❌ partial (unique/sequence opts)
ModelSQS-style queue, SQL APIGo job runnerlog + queue platform

The structural difference is one design decision: job queues delete (or archive) on completion, so a message belongs to whoever claimed it first. That forecloses fan-out and replay permanently. Vulkan retains the log and moves lifecycle into per-group delivery state — same claiming machinery, applied per consumer group instead of globally. The architecture page shows exactly how.

”Isn’t this just a job queue with extra steps?”

Section titled “”Isn’t this just a job queue with extra steps?””

For your first use case — background jobs — Vulkan behaves exactly like a great job queue, and you can use it as one (one lifecycle group, ignore everything else; the cursor machinery costs nothing if unused).

The bet is about your second and third use cases. The team that adopts a job queue almost always ends up, eighteen months later, also running:

  • an events pipeline (Kafka/Kinesis) because product analytics and a new service both needed the order stream the job queue had been deleting,
  • a pub/sub layer (SNS/RabbitMQ) because three services needed the same notification and the job queue could only give it to one,
  • an outbox + relay because the broker introduced the dual-write problem the Postgres queue never had.

Each addition is individually reasonable; the sum is the three-broker sprawl that Why Vulkan opens with. Vulkan’s pitch to job-queue users is simple: same start, different ceiling.

Those are workflow engines — they orchestrate multi-step, long-running functions (often with a Postgres queue underneath, as in Hatchet’s case). Different layer of the stack: a workflow engine needs a durable message platform; a message platform doesn’t need a workflow engine. Vulkan is the platform layer — and a code-first workflow layer on top of it is on the roadmap, built on the same log, with the same transactional guarantees.