Skip to content
Get started
Get started
Architecture: SQLite and PostgreSQL Queue Engines for Bun
View Markdown
architecture · overview

Inside the bunqueue architecture.

bunqueue has two execution topologies behind one server protocol: a synchronous sharded memory/SQLite engine, and a database-authoritative PostgreSQL 15–18 engine for multiple brokers. This section maps both and identifies which diagrams belong to which path.

System overviewclient, server, persistence
client layer
Queue.add() TcpPool
Worker.process() TcpPool
↓ msgpack over TCP :6789
server layer
QueueManager · memory / SQLite
N shards auto-detected: Shard 0, Shard 1, ... Shard N
jobIndex
completedJobs
customIdMap
jobResults
local persistence path
WriteBuffer
SQLite WAL mode
PostgreSQL multi-broker path
PostgresQueueManager
Bun.SQL pool + transactions
PostgreSQL authoritative state
background tasks
Scheduler
Stall detection
DLQ maintenance
Cleanup
LayerPurposeKey Components
ClientSDK for applicationsQueue, Worker, FlowProducer, TcpPool
ServerRequest handlingTcpServer, HttpServer, Handlers
ApplicationOrchestrationQueueManager, Operations, Managers
DomainBusiness logicShard, PriorityQueue, DLQ
InfrastructureStorage and external systemsSQLite, PostgreSQL, S3 Backup, Scheduler
SharedUtilitiesHash, Lock, LRU, MinHeap
SectionDescription
Client SDKTCP connection, job submission, worker processing
Domain LayerSharding, priority queues, DLQ logic
Application LayerOperations flow, background tasks
PersistenceSQLite configuration, write buffering, and recovery
Storage BackendsPostgreSQL transactions, multi-broker fencing, and topology
Data StructuresCore algorithms and complexities
TCP ProtocolWire format and commands
Cron SchedulerEvent-driven scheduling, timezone support, persistence

The shard, heap, lock, write-buffer, and complexity sections below describe the memory/SQLite QueueManager. PostgreSQL servers select PostgresQueueManager instead: PostgreSQL owns claim ordering, leases, shared policy, dependencies, events, cron, and terminal state. The TCP/HTTP client contract remains common.

In memory/SQLite mode, jobs are distributed across N independent shards (auto-detected from CPU cores) using FNV-1a hash:

SHARD_COUNT = calculateShardCount() // Power of 2, based on CPU cores, max 64
SHARD_MASK = SHARD_COUNT - 1
shardIndex = fnv1a(queueName) & SHARD_MASK // src/shared/hash.ts
// Examples: 4 cores → 4 shards, 10 cores → 16 shards, 64+ cores → 64 shards

Benefits:

  • Auto-scales with hardware (power of 2, max 64)
  • Parallel operations on different queues
  • Reduced lock contention
  • Bitwise AND faster than modulo

Each shard contains a 4-ary heap instead of binary:

  • Better cache locality (children fit in cache line)
  • Fewer tree levels (8 vs 16 for 65k items)
  • O(log₄ n) operations

Jobs batch before SQLite write:

Buffer 100 jobs
Multi-row INSERT 186,384 jobs/s median in the published public on-disk addBulk workload

Flushes after 10ms or when 100 jobs are buffered, whichever comes first.

  • Buffered: up to 10 ms loss risk; 186,384 jobs/s median in the published public on-disk Embedded addBulk workload
  • Durable: immediate persistence; 60,835 ops/s median for published sequential Embedded adds

Heap entries use generation tracking:

Remove: Delete from index (O(1)), mark heap entry stale
Pop: Skip entries where generation != current
Compact: Rebuild when >20% stale

Acquire in order to prevent deadlocks:

1. jobIndex (read-only)
2. completedJobs (check before lock)
3. shardLocks[N]
4. processingLocks[N]
CollectionLimitEviction
completedJobs50,000FIFO batch
jobResults10,000LRU
jobLogs10,000LRU
customIdMap50,000LRU
DLQ per queue10,000FIFO
OperationComplexity
PUSHO(log₄ n)
PULLO(log₄ n)
ACKO(1)
ACK batchO(shards)
Job lookupO(1)
StatsO(1)