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';constclient=awaitMongoClient.connect('mongodb+srv://user:pw@cluster.example.net/app',);constusers=client.db('app').collection('users');// High-level CRUD helpersconstdoc=awaitusers.findOne({_id: newObjectId(id)});awaitusers.insertMany([{name: 'alice'},{name: 'bob'}]);awaitusers.updateOne({name: 'alice'},{$set: {active: true}});// Low-level: any MongoDB command, wire-format passthroughconstres=awaitclient.db('app').command({find: 'users',filter: {status: 'active'},limit: 10,});// Sessions + transactionsconstsession=client.startSession();awaitsession.withTransaction(async()=>{awaitusers.updateOne({_id: a},{$inc: {balance: -100}},{ session });awaitusers.updateOne({_id: b},{$inc: {balance: 100}},{ session });});// Change streamsforawait(constchangeofusers.watch()){console.log(change.operationType,change.fullDocument);}awaitclient.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 loadedcd bench && bash scripts/matrix.sh
bun run summarize.tsMIT