bson, bson-ext, and mongodb are core packages for working with MongoDB data in JavaScript, but they serve distinct roles. bson is the official, pure-Javascript implementation of the BSON (Binary JSON) spec, used to serialize and deserialize data into the binary format MongoDB uses. bson-ext was historically an optional C++ addon designed to speed up bson operations, but it is now deprecated and unsupported. mongodb is the official high-level database driver that manages connections, query execution, and automatically handles BSON conversion under the hood. Understanding the relationship between the low-level serializer (bson) and the full driver (mongodb) is critical for avoiding redundancy and performance pitfalls.
When working with MongoDB in the JavaScript ecosystem, developers often encounter three specific packages: bson, bson-ext, and mongodb. While they sound related, they solve different problems. One is a data format serializer, one is a deprecated performance patch, and one is the full database driver. Let's break down exactly how they differ and how to use them correctly in modern architectures.
The most important distinction is between the data format and the database client.
bson is purely a serializer/deserializer. It knows nothing about networks, connections, or databases. Its only job is to turn JavaScript objects into BSON binary buffers and vice versa.
// bson: Pure serialization
const { BSON } = require('bson');
const doc = { name: "Alice", active: true };
// Serialize to a Buffer
const buffer = BSON.serialize(doc);
// Deserialize back to an object
const restored = BSON.deserialize(buffer);
console.log(restored.name); // "Alice"
mongodb is the full driver. It handles TCP connections, authentication, connection pooling, and query execution. It uses bson internally so you don't have to manually serialize data when running queries.
// mongodb: Full database interaction
const { MongoClient } = require('mongodb');
const client = new MongoClient('mongodb://localhost:27017');
async function run() {
await client.connect();
const collection = client.db('test').collection('users');
// No manual serialization needed here
await collection.insertOne({ name: "Alice", active: true });
const user = await collection.findOne({ name: "Alice" });
console.log(user.name); // "Alice"
await client.close();
}
bson-ext attempted to be a faster version of bson by using C++ bindings. However, it is no longer relevant (see the deprecation section below).
Historically, parsing large binary blobs in JavaScript was slow. bson-ext was created to solve this by offloading work to C++.
bson-ext (Deprecated) required native compilation. If your build environment didn't have the right C++ toolchain, installation failed. It also lagged behind bson in feature updates.
// bson-ext: DO NOT USE
// This pattern is obsolete and will likely fail on Node 18+
const BSON = require('bson-ext');
const buffer = BSON.serialize({ id: 123 });
bson (Current Standard) has been heavily optimized. The maintainers have rewritten critical paths in pure JavaScript that now rival or exceed the old C++ performance for most web workloads, without the headache of native dependencies.
// bson: Optimized Pure JS
const { BSON } = require('bson');
// Modern usage is fast and requires no compilation
const largeDoc = { data: new Array(10000).fill(1) };
const start = Date.now();
BSON.serialize(largeDoc);
console.log(`Serialized in ${Date.now() - start}ms`);
mongodb automatically selects the best available BSON parser. In recent versions, it defaults to the highly optimized bson package. You get the performance benefits without managing the dependency yourself.
// mongodb: Automatic optimization
const { MongoClient } = require('mongodb');
// The driver internally picks the fastest BSON implementation
const client = new MongoClient('mongodb://localhost:27017', {
// No need to manually inject a BSON library anymore
});
bson-extIt is critical to understand that bson-ext is deprecated. The official MongoDB documentation and npm page explicitly state that it is no longer maintained.
bson-ext would break until a maintainer updated the C++ code.bson-ext today means your project may fail to install on modern CI/CD pipelines or cloud runtimes (like AWS Lambda or Vercel) that use recent Node versions.bson package is now the default and recommended approach for everyone.// ❌ WRONG: Installing deprecated package
// npm install bson-ext
// ✅ RIGHT: Rely on the maintained version
// npm install bson
// OR just install the driver which includes it
// npm install mongodb
Your choice depends entirely on whether you are talking to a database or just moving data.
You are building an Express or Fastify server that needs to read/write to MongoDB.
mongodbbson alone cannot connect to a database.// Using mongodb driver
const { MongoClient } = require('mongodb');
const client = new MongoClient(process.env.MONGO_URI);
app.get('/users', async (req, res) => {
const db = client.db('myapp');
// Driver handles serialization/deserialization automatically
const users = await db.collection('users').find({}).toArray();
res.json(users);
});
You have a file system full of .bson files (perhaps backups or logs) and need to read them without spinning up a database server.
bson// Using bson for file processing
const { BSON } = require('bson');
const fs = require('fs');
const fileBuffer = fs.readFileSync('backup.bson');
const data = BSON.deserialize(fileBuffer);
console.log(`Restored ${data.items.length} items from file.`);
You are updating an old codebase that explicitly imports bson-ext.
bson.// Old Code
// const BSON = require('bson-ext');
// New Code
const { BSON } = require('bson');
// The methods serialize/deserialize work the same way
const doc = BSON.deserialize(oldBuffer);
Despite their different roles, bson and mongodb share the same type definitions because mongodb relies on bson. This means special types like ObjectId, Date, and Decimal128 behave consistently.
Both packages expose the ObjectId generator. Whether you create it for a manual buffer or a database insert, the format is identical.
// bson: Creating an ID manually
const { ObjectId } = require('bson');
const id = new ObjectId();
// mongodb: Creating an ID for insertion
const { MongoClient } = require('mongodb');
// Inside a driver context, ObjectId is the same class
const doc = { _id: new ObjectId(), name: "Test" };
JavaScript Date objects map to BSON Date types in both libraries. Binary data (like images) is handled via the Binary type.
// bson: Manual binary creation
const { Binary, BSON } = require('bson');
const bin = new Binary(Buffer.from("image data"));
const buf = BSON.serialize({ img: bin });
// mongodb: Storing binary in DB
const { MongoClient } = require('mongodb');
// Driver accepts the same Binary type
await collection.insertOne({ img: new Binary(Buffer.from("image data")) });
For financial data requiring high precision, both use Decimal128 to avoid floating-point errors.
// bson: Parsing decimal string
const { Decimal128, BSON } = require('bson');
const price = Decimal128.fromString("19.99");
// mongodb: Saving precise value
const { MongoClient } = require('mongodb');
await collection.insertOne({ price: Decimal128.fromString("19.99") });
| Feature | bson | bson-ext | mongodb |
|---|---|---|---|
| Primary Role | Data Serializer/Parser | Deprecated C++ Accelerator | Database Driver |
| Network Capable | ❌ No | ❌ No | ✅ Yes |
| Maintenance Status | ✅ Active | ❌ Deprecated | ✅ Active |
| Installation | npm install bson | npm install bson-ext (Avoid) | npm install mongodb |
| Native Bindings | No (Pure JS) | Yes (C++) | Optional (Auto-detected) |
| Use Case | File parsing, custom protocols | None | App backends, APIs |
mongodb is the hammer you need for 95% of tasks. It builds the house (connects to the DB, runs queries). It already contains the nails (bson), so you don't need to buy them separately unless you have a very specific need.
bson is the nail. Use it directly only if you are doing carpentry without a hammer—like reading binary files or implementing a custom network protocol that speaks BSON but doesn't use MongoDB.
bson-ext is a broken, rusty tool from ten years ago. Leave it in the past. Modern JavaScript engines are fast enough that the pure-JS bson implementation is the standard for performance and reliability.
Final Thought: Stick to mongodb for database work and bson for data manipulation. Ignore bson-ext completely to ensure your application remains secure, installable, and maintainable for years to come.
Choose bson if you need to manually serialize or deserialize BSON data outside of a direct database connection, such as parsing stored binary files, working with GridFS chunks directly, or interfacing with other systems that exchange BSON buffers. It is the standard, maintained library for pure JavaScript environments and is automatically included when you install the mongodb driver.
Do NOT choose bson-ext for any new project. This package is deprecated, no longer maintained, and incompatible with modern Node.js versions and the current bson API. Relying on it introduces security risks and build failures. The performance gains it once offered are now available through the optimized pure-JS bson package or the native bindings included in mongodb.
Choose mongodb for virtually all application development requiring database access. It provides the complete toolkit for connecting to clusters, managing pools, executing queries, and handling transactions. It internally uses bson for data conversion, so you rarely need to install bson separately unless you are doing low-level binary manipulation. It is the only choice for building robust, production-ready backend services or serverless functions interacting with MongoDB.
BSON is short for "Binary JSON," and is the binary-encoded serialization of JSON-like documents. You can learn more about it in the specification.
Releases are created automatically and signed using the Node team's GPG key. All release packages provided as part of a GitHub release are signed. To verify the provided packages, download the key and import it using gpg:
gpg --import node-driver.asc
The GitHub release contains a detached signature file for the NPM package (named
bson-X.Y.Z.tgz.sig).
The following command returns the link npm package.
npm view bson@vX.Y.Z dist.tarball
Using the result of the above command, a curl command can return the official npm package for the release.
To verify the integrity of the downloaded package, run the following command:
gpg --verify bson-X.Y.Z.tgz.sig bson-X.Y.Z.tgz
[!Note] No GPG verification is done when using npm to install the package. The contents of the GitHub tarball and npm's tarball are identical.
Releases published to the npm registry also include a provenance attestation, which cryptographically links the package to its source repository and build workflow. To verify provenance:
npm audit signatures
Think you've found a bug? Want to see a new feature in bson? Please open a case in our issue management tool, JIRA:
Bug reports in JIRA for the NODE driver project are public.
To build a new version perform the following operations:
npm install
npm run build
When using a bundler or Node.js you can import bson using the package name:
import { BSON, EJSON, ObjectId } from 'bson';
// or:
// const { BSON, EJSON, ObjectId } = require('bson');
const bytes = BSON.serialize({ _id: new ObjectId() });
console.log(bytes);
const doc = BSON.deserialize(bytes);
console.log(EJSON.stringify(doc));
// {"_id":{"$oid":"..."}}
If you are working directly in the browser without a bundler please use the .mjs bundle like so:
<script type="module">
import { BSON, EJSON, ObjectId } from './lib/bson.mjs';
const bytes = BSON.serialize({ _id: new ObjectId() });
console.log(bytes);
const doc = BSON.deserialize(bytes);
console.log(EJSON.stringify(doc));
// {"_id":{"$oid":"..."}}
</script>
npm install bson
Only the following version combinations with the MongoDB Node.js Driver are considered stable.
bson@1.x | bson@4.x | bson@5.x | bson@6.x | bson@7.x | |
|---|---|---|---|---|---|
mongodb@7.x | N/A | N/A | N/A | N/A | ✓ |
mongodb@6.x | N/A | N/A | N/A | ✓ | N/A |
mongodb@5.x | N/A | N/A | ✓ | N/A | N/A |
mongodb@4.x | N/A | ✓ | N/A | N/A | N/A |
mongodb@3.x | ✓ | N/A | N/A | N/A | N/A |
| Param | Type | Default | Description |
|---|---|---|---|
| text | string | ||
| [options] | object | Optional settings | |
| [options.relaxed] | boolean | true | Attempt to return native JS types where possible, rather than BSON types (if true) |
Parse an Extended JSON string, constructing the JavaScript value or object described by that string.
Example
const { EJSON } = require('bson');
const text = '{ "int32": { "$numberInt": "10" } }';
// prints { int32: { [String: '10'] _bsontype: 'Int32', value: '10' } }
console.log(EJSON.parse(text, { relaxed: false }));
// prints { int32: 10 }
console.log(EJSON.parse(text));
| Param | Type | Default | Description |
|---|---|---|---|
| value | object | The value to convert to extended JSON | |
| [replacer] | function | array | A function that alters the behavior of the stringification process, or an array of String and Number objects that serve as a whitelist for selecting/filtering the properties of the value object to be included in the JSON string. If this value is null or not provided, all properties of the object are included in the resulting JSON string | |
| [space] | string | number | A String or Number object that's used to insert white space into the output JSON string for readability purposes. | |
| [options] | object | Optional settings | |
| [options.relaxed] | boolean | true | Enabled Extended JSON's relaxed mode |
| [options.legacy] | boolean | true | Output in Extended JSON v1 |
Converts a BSON document to an Extended JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.
Example
const { EJSON } = require('bson');
const Int32 = require('mongodb').Int32;
const doc = { int32: new Int32(10) };
// prints '{"int32":{"$numberInt":"10"}}'
console.log(EJSON.stringify(doc, { relaxed: false }));
// prints '{"int32":10}'
console.log(EJSON.stringify(doc));
| Param | Type | Description |
|---|---|---|
| bson | object | The object to serialize |
| [options] | object | Optional settings passed to the stringify function |
Serializes an object to an Extended JSON string, and reparse it as a JavaScript object.
| Param | Type | Description |
|---|---|---|
| ejson | object | The Extended JSON object to deserialize |
| [options] | object | Optional settings passed to the parse method |
Deserializes an Extended JSON object into a plain JavaScript object with native/BSON types
It is our recommendation to use BSONError.isBSONError() checks on errors and to avoid relying on parsing error.message and error.name strings in your code. We guarantee BSONError.isBSONError() checks will pass according to semver guidelines, but errors may be sub-classed or their messages may change at any time, even patch releases, as we see fit to increase the helpfulness of the errors.
Any new errors we add to the driver will directly extend an existing error class and no existing error will be moved to a different parent class outside of a major release.
This means BSONError.isBSONError() will always be able to accurately capture the errors that our BSON library throws.
Hypothetical example: A collection in our Db has an issue with UTF-8 data:
let documentCount = 0;
const cursor = collection.find({}, { utf8Validation: true });
try {
for await (const doc of cursor) documentCount += 1;
} catch (error) {
if (BSONError.isBSONError(error)) {
console.log(`Found the troublemaker UTF-8!: ${documentCount} ${error.message}`);
return documentCount;
}
throw error;
}
js-bson requires the atob, btoa and TextEncoder globals. Older versions of React Native did not support these global objects, and so
js-bson v5.4.0 added support for bundled polyfills for these globals. Newer versions
of Hermes includes these globals, and so the polyfills for are no longer needed in the js-bson package.
If you find yourself on a version of React Native that does not have these globals, either:
>=5.4.0 and <7.0.0One additional polyfill, crypto.getRandomValues is recommended and can be installed with the following command:
npm install --save react-native-get-random-values
The following snippet should be placed at the top of the entrypoint (by default this is the root index.js file) for React Native projects using the BSON library. These lines must be placed for any code that imports BSON.
// Required Polyfills For ReactNative
import 'react-native-get-random-values';
Finally, import the BSON library like so:
import { BSON, EJSON } from 'bson';
This will cause React Native to import the node_modules/bson/lib/bson.rn.cjs bundle (see the "react-native" setting we have in the "exports" section of our package.json.)
The "exports" definition in our package.json will result in BSON's CommonJS bundle being imported in a React Native project instead of the ES module bundle. Importing the CommonJS bundle is necessary because BSON's ES module bundle of BSON uses top-level await, which is not supported syntax in React Native's runtime hermes.
undefined get converted to null?The undefined BSON type has been deprecated for many years, so this library has dropped support for it. Use the ignoreUndefined option (for example, from the driver ) to instead remove undefined keys.
This library looks for toBSON() functions on every path, and calls the toBSON() function to get the value to serialize.
const BSON = require('bson');
class CustomSerialize {
toBSON() {
return 42;
}
}
const obj = { answer: new CustomSerialize() };
// "{ answer: 42 }"
console.log(BSON.deserialize(BSON.serialize(obj)));