OpenRadar

Project · Python · Added June 17, 2026

honker

Honker adds Postgres-style NOTIFY/LISTEN, durable task queues, pub/sub, and streams to SQLite — no Redis or message broker required.

2,859 stars 69 forks View on GitHub

Honker

Overview

Honker is a SQLite extension with language bindings that bring Postgres-style NOTIFY/LISTEN semantics to SQLite, along with durable pub/sub, at-least-once task queues, event streams, and cron scheduling. It hit 2,800 GitHub stars within two months of its April 2026 launch, driven by a Simon Willison endorsement and a growing developer appetite for SQLite-native infrastructure.

The project is created by Russell Romney, a developer who’s clearly spent enough time fighting the “just add Redis” reflex in SQLite-based applications. The core insight is simple but powerful: if SQLite is your primary datastore, your queue should live in the same file. No second database, no broker process, no dual-write problem between your business tables and your job queue. One .db file, one transaction, atomic commits.

The problem honker solves is one that nearly every SQLite-backed application eventually hits. You start with SQLite because it’s fast, reliable, and zero-config. Then you need background jobs. The standard answer is “add Redis and Celery” or “add RabbitMQ.” Suddenly you have a second datastore with its own backup story, a broker process to run and monitor, and a dual-write problem where your business insert and queue enqueue can fail independently. Honker eliminates all of that by making the queue just rows in a table with a partial index, accessed through a SQLite loadable extension.

Why it matters

SQLite is having a moment. The “SQLite for production” movement has been building for years — Litestream for replication, LiteFS for distributed reads, Turso for edge deployment, and frameworks like Drizzle and Kysely treating SQLite as a first-class target. But the missing piece has always been the infrastructure layer: pub/sub, task queues, and scheduling. Those have been Redis/Celery/RabbitMQ territory, forcing developers to run a second data layer even when SQLite handles everything else.

Honker fills that gap. It’s not trying to replace Postgres or compete with distributed message brokers. It’s solving the specific problem of “I chose SQLite, and now I need a queue without adding Redis.” That’s a real pain point, and the project’s rapid traction — nearly 3K stars, bindings for 10+ languages, and Simon Willison’s stamp of approval within weeks — reflects genuine demand.

The timing connects to a broader shift in how developers think about architecture. The “add Redis for everything” era is being challenged by projects that push more functionality into SQLite. Drizzle brought type-safe SQL. Turso brought edge replication. Litestream brought streaming backups. Honker brings the messaging layer. Together, they’re making SQLite viable for a class of applications that previously required a full Postgres or MySQL setup plus a message broker.

Key Features

Transactional Outbox Pattern. The killer feature. You can enqueue a job inside the same transaction as your business write. INSERT INTO orders and queue.enqueue(...) commit together or roll back together. No partial state, no lost jobs, no need for the outbox table pattern that Postgres developers have been hand-rolling for years. Simon Willison specifically highlighted this as a SQLite implementation of the transactional outbox pattern.

Single-Digit-Millisecond Wake Latency. SQLite has no server-side push channel, so honker uses a PRAGMA data_version watcher that checks every millisecond. When the counter changes, listeners re-read indexed state. The result is cross-process delivery in single-digit milliseconds without polling overhead. A hundred subscribers share one watcher, and idle listeners run zero SELECTs until work arrives.

Durable At-Least-Once Queues. The queue implementation supports retries, delayed jobs, priority ordering, visibility timeouts, dead-letter rows, and task result storage. Claim is a single UPDATE ... RETURNING through a partial index on (queue, priority DESC, run_at, id). Ack is a single DELETE. Retry-exhausted jobs move to a dead-letter table, so claim speed depends on active jobs, not queue history.

10+ Language Bindings. Python, Node.js, Rust, Go, Ruby, Bun, Elixir, .NET/C#, Java/JVM, and Kotlin — all sharing the same underlying SQLite schema and extension. A Python worker can claim jobs written by Node.js. A Go service can enqueue work consumed by Ruby. The extension and schema are the compatibility layer, not a protocol or wire format.

Built-in Cron and Scheduling. Time-trigger scheduling with standard cron expressions, 6-field cron, and @every <duration> interval syntax. Register periodic tasks with honker_scheduler_register(), tick the scheduler on each wake, and get back the list of tasks that are due. No external cron daemon needed for simple periodic work.

Named Locks and Rate Limiters. Distributed-style primitives for single-machine coordination: honker_lock_acquire('backup', 'me', 60) for advisory locks with TTL, and honker_rate_limit_try('api', 10, 60) for sliding-window rate limits. These cover the common patterns where developers reach for Redis just for SET NX or rate limiting.

Framework-Agnostic ORM Integration. No framework plugins required. Load the extension on your ORM connection, run honker_bootstrap(), and call SQL functions inside transactions. Works with SQLAlchemy, SQLModel, Django, Drizzle, Kysely, SQLx, GORM, ActiveRecord, Ecto, Hibernate, jOOQ, MyBatis, and Exposed.

Use Cases

Pros and Cons

Pros:

Cons:

Getting Started

# Install
pip install honker

# Quick example — enqueue and consume
python -c "
import honker

db = honker.open('app.db')
emails = db.queue('emails')

# Enqueue inside a transaction
with db.transaction() as tx:
    tx.execute('INSERT INTO orders (user_id) VALUES (?)', [42])
    emails.enqueue({'to': 'alice@example.com'}, tx=tx)

# Consume in another process
import asyncio
async def worker():
    async for job in emails.claim('worker-1'):
        print(f'Sending to {job.payload[\"to\"]}')
        job.ack()

asyncio.run(worker())
"

For Node.js:

npm install @russellthehippo/honker-node

For the SQL extension directly:

.load ./libhonker_ext
SELECT honker_bootstrap();
INSERT INTO _honker_live (queue, payload) VALUES ('emails', '{"to":"alice"}');
SELECT honker_claim_batch('emails', 'worker-1', 32, 300);

Alternatives

Huey — A Python-native task queue that supports SQLite, Redis, and in-memory backends. Huey is more mature and has a cleaner Python API, but it’s Python-only and doesn’t offer the cross-language binding story that honker provides. Choose Huey if you’re Python-only and want a battle-tested queue library.

pg-boss — The Postgres-side gold standard for job queues using LISTEN/NOTIFY. If you’re already running Postgres, pg-boss is the better choice — it’s production-proven and handles multi-server deployments. Honker exists for the cases where Postgres is overkill and SQLite is the right database.

Redis + Celery — The traditional answer for Python background jobs. Celery is feature-complete with chains, chords, groups, and a massive ecosystem. But it requires running Redis (or RabbitMQ) as a broker, which adds operational complexity. Honker trades feature breadth for simplicity: if your queue needs are straightforward, honker eliminates an entire infrastructure component.

Verdict

Honker is the most practical SQLite extension I’ve seen this year. It doesn’t try to be everything — it’s single-machine, file-backed, and explicitly doesn’t do workflow DAGs or distributed locking. What it does do is solve the “I need a queue but don’t want Redis” problem in a principled way, with atomic transactions, cross-language bindings, and performance that’s good enough for most applications. The 2.8K stars in two months and Simon Willison’s endorsement reflect genuine developer interest, not marketing. If you’re building on SQLite and you’ve been putting off adding a job queue because you don’t want the infrastructure overhead, honker is worth evaluating today. It’s alpha software, so don’t ship it in your banking system yet — but for side projects, prototypes, and SQLite-backed web apps, it’s a compelling alternative to the Redis/Celery stack.

Related

Shared tags