Pure-TypeScript MongoDB wire-protocol driver. Runs on Node.js 22+ and Bun, and compiles to a native binary via Perry (LLVM AOT). Zero runtime dependencies — BSON, OP_MSG framing, SCRAM auth, TLS, SDAM, transactions, change streams, and GridFS are all implemented in hand-written TypeScript.
npm install @perryts/mongodb
# or
bun add @perryts/mongodbimport { MongoClient, ObjectId } from '@perryts/mongodb';
const client = await MongoClient.connect(
'mongodb+srv://user:pw@cluster.example.net/app',
);
const users = client.db('app').collection('users');
// High-level CRUD helpers
const doc = await users.findOne({ _id: new ObjectId(id) });
await users.insertMany([{ name: 'alice' }, { name: 'bob' }]);
await users.updateOne({ name: 'alice' }, { $set: { active: true } });
// Low-level: any MongoDB command, wire-format passthrough
const res = await client.db('app').command({
find: 'users',
filter: { status: 'active' },
limit: 10,
});
// Sessions + transactions
const session = client.startSession();
await session.withTransaction(async () => {
await users.updateOne({ _id: a }, { $inc: { balance: -100 } }, { session });
await users.updateOne({ _id: b }, { $inc: { balance: 100 } }, { session });
});
// Change streams
for await (const change of users.watch()) {
console.log(change.operationType, change.fullDocument);
}
await client.close();- Pure TypeScript, zero runtime deps. No
bson, nomongodb-connection-string-url, no native addons. - Perry AOT compilable. Same source compiles to a static native binary via the Perry toolchain.
- Runs on Node 22+ and Bun. No fallback shims.
- MongoDB 5.0+ only. OP_MSG wire protocol only; no OP_QUERY.
- No CSFLE (client-side field level encryption). Deferred until a pure-TS mongocrypt replacement exists.
- No zstd/snappy compression. zlib only (OP_COMPRESSED).
10 operations, the same MongoDB 7.0 instance over loopback, mongo's
official sample_mflix / sample_analytics / sample_training
fixtures. Every cell verifies cross-driver equivalence by hashing the
first iteration's result — all 7 cells produced byte-identical results
across all 10 operations.
Latency, mean ms / op (lower is better):
| op | bun mongodb | bun mongoose | bun perryts | node mongodb | node mongoose | node perryts | perry-aot perryts |
|---|---|---|---|---|---|---|---|
| findOne_by_id_movie | 0.70 | 0.46 | 0.35 | 0.35 | 0.52 | 0.26 | 0.24 |
| find_movies sort+limit_50 | 12.05 | 10.35 | 9.10 | 10.46 | 10.49 | 8.63 | 8.49 |
| count_grades_score_gte_80 | 35.25 | 35.08 | 29.55 | 34.61 | 32.59 | 28.80 | 28.62 |
| distinct_movies_genres_year_2000 | 8.14 | 7.85 | 6.78 | 7.22 | 10.17 | 6.76 | 6.60 |
| aggregate_lookup_customer | 0.85 | 1.31 | 0.81 | 0.94 | 1.33 | 0.65 | 0.63 |
| aggregate_movies_group_by_year | 14.24 | 13.38 | 11.19 | 13.84 | 15.50 | 10.93 | 11.45 |
| cursor_all_zips (~30k docs) | 83.58 | 82.13 | 80.71 | 72.60 | 97.68 | 92.57 | n/a |
| insertMany_1000 | 7.07 | 9.69 | 8.69 | 7.75 | 8.69 | 7.23 | 39.00 |
| updateMany_inc_touches | 35.93 | 38.30 | 28.65 | 40.23 | 34.89 | 29.34 | 28.20 |
| deleteMany_1000 | 13.17 | 15.87 | 10.25 | 16.08 | 11.14 | 10.55 | 66.90 |
@perryts/mongodb is the fastest (or tied-fastest) driver on 8 of 9
applicable ops under Bun and Node, and on 5 of 9 under Perry-AOT.
The remaining gap is on bulk-write paths under Perry-AOT
(insertMany_1000, deleteMany_1000) — these are slower than the
official C-extension driver because Perry-AOT's per-method-call
dispatch on BufferWriter primitives is currently ~10× heavier than
V8's IC-cached path. That's a Perry codegen concern, not an algorithmic
one; the same source under Bun and Node clears the official driver on
the same workload.
cursor_all_zips is intentionally skipped on Perry-AOT — the
~30k-document sequential getMore chain currently runs on a 1ms-resolution
clock there, which produces noisy quantized samples. It will be brought
back when Perry exposes performance.now() or process.hrtime.
The full harness — three runtimes × three drivers × ten operations,
with cross-cell result verification — lives in
bench/. To
reproduce locally:
mongosh # mongo://127.0.0.1:27017 with sample_mflix / sample_analytics / sample_training loaded
cd bench && bash scripts/matrix.sh
bun run summarize.tsMIT