Stoolap/Node: A Native Node.js Driver That's Surprisingly Fast
I’ve been working on Stoolap for a while now – an embedded SQL database written in pure Rust. It started as a Go project, grew into something much bigger, and recently hit a point where I thought: okay, this thing is fast, but how do people actually use it outside of Rust?
The answer, for a lot of developers, is Node.js. So I built @stoolap/node – a native driver powered by NAPI-RS that gives you direct access to Stoolap from JavaScript and TypeScript.
No HTTP server in between. No serialization overhead. Just your Node.js process talking directly to the database engine through native bindings.
Look, SQLite is great. I use it myself. It’s battle-tested, well-documented, and everywhere. But there are things it doesn’t do well – or doesn’t do at all.
Stoolap has MVCC transactions, a cost-based query optimizer, parallel execution, semantic query caching, and temporal queries with AS OF. These aren’t checkbox features; they actually show up in real workloads.
But the question I kept getting was: is it actually faster?
Fair question. So I ran the benchmarks.
I wrote a comprehensive benchmark suite that runs 53 identical SQL operations against both @stoolap/node and better-sqlite3 (the gold standard for SQLite in Node.js). Same data, same queries, same machine.
The setup: 10,000 rows, a mix of point queries, joins, aggregations, subqueries, and analytical operations. Everything runs in-memory to keep it fair.
Here’s the summary:
I wasn’t expecting that ratio, honestly. Let me break down where the biggest gaps are.
The differences aren’t small. Some of these numbers surprised me:
The COUNT DISTINCT result at 138x faster is probably the most dramatic. Stoolap maintains internal data structures that make distinct counting nearly free, while SQLite has to scan and deduplicate every time.
The subquery performance (EXISTS, NOT EXISTS, IN, NOT IN) comes from Stoolap’s semi-join optimization – it builds a HashSet from the subquery result and probes it, rather than running correlated subqueries row by row.
Let’s be honest about where SQLite is faster:
These are all small margins – mostly in the 1.0x to 1.6x range. SQLite’s single-row operations benefit from decades of optimization on that specific path. The B-tree page cache is incredibly well-tuned for point lookups.
But notice the pattern: SQLite’s wins are on simple, single-row operations where both databases are already sub-millisecond. Stoolap’s wins are on the analytical and complex queries where the difference is 10x to 100x+.
Three things, mainly:
MVCC without locks. Stoolap uses multi-version concurrency control, which means readers never block writers. In the Node.js driver, this means your async queries don’t stall behind pending writes.
Cost-based optimizer. Instead of always doing a sequential scan or always using an index, Stoolap estimates the cost of different execution strategies and picks the cheapest one. For queries with multiple conditions or joins, this makes a huge difference.
Parallel execution. Queries over large datasets automatically parallelize using Rayon’s work-stealing scheduler. Filters, hash joins, sorts, and distinct operations all scale across cores.
The API should feel familiar if you’ve used better-sqlite3 or any other embedded database driver:
Both async and sync APIs are available. Async runs on the libuv thread pool so it won’t block your event loop. Sync is slightly faster for simple operations if you’re in a context where blocking is fine (scripts, CLI tools, tests).
For hot paths, prepared statements skip parsing entirely:
Transactions work the way you’d expect:
In-memory is great for benchmarks, but real applications need persistence. Stoolap uses WAL (Write-Ahead Logging) with configurable durability:
Data survives process restarts. Snapshots run periodically in the background so WAL doesn’t grow forever.
Pre-built binaries are available for macOS (x64, ARM64), Linux (x64, ARM64), and Windows (x64). No Rust toolchain required.
If you want to build from source:
The full API documentation is in the driver docs.
The Node.js driver is at v0.3.1 right now. It covers the full Stoolap API – databases, transactions, prepared statements, batch operations, and all the query methods.
I’m planning to add connection pooling helpers and streaming query support in upcoming releases. If you run into issues or have feature requests, open an issue on GitHub.
Give it a try and let me know what you think.
Alex Chen
Senior Tech EditorCovering the latest in consumer electronics and software updates. Obsessed with clean code and cleaner desks.