MongoDBThe BSON Format

BSON

MongoDB stores documents as BSON — Binary JSON — not plain text JSON. BSON is a binary-encoded serialization format that extends JSON's model with additional data types and metadata designed for fast traversal, efficient storage, and unambiguous typing.

Why Binary Instead of Text JSON?
  • Speed of parsing. BSON encodes the length of each element up front, so a driver can skip over fields without scanning byte-by-byte the way a JSON text parser must.

  • Richer types. Plain JSON only has strings, numbers, booleans, null, arrays, and objects. BSON adds dates, binary data, decimals with exact precision, and a dedicated ID type (ObjectId), among others.

  • Traversability. Because each BSON value is length-prefixed, MongoDB can jump directly to a field deep in a document without re-parsing everything before it.

  • Efficient on-disk storage compared to storing equivalent text JSON, particularly for numeric-heavy documents.

Note
BSON documents are not necessarily smaller than the equivalent JSON text — the length prefixes and type tags add some overhead per field. The win is in parse and traversal speed, not raw byte count.
JSON vs BSON

Aspect

JSON

BSON

Format

Human-readable text

Binary

Types

string, number, boolean, null, array, object

All JSON types plus Date, ObjectId, Binary, Decimal128, RegExp, Timestamp, Int32/Int64 distinction, and more

Numbers

Single "number" type (double precision in most parsers)

Distinguishes Int32, Int64, Double, and exact-precision Decimal128

Traversal

Must scan/parse sequentially

Length-prefixed — can skip fields

Where you see it

REST APIs, config files, mongoexport output

On disk, over the wire, in mongodump output

Common BSON Types

BSON Type

mongosh Example

Notes

Double

3.14

Default for decimal numbers typed in mongosh

String

"hello"

UTF-8 encoded

Object

{ a: 1 }

An embedded document

Array

[1, 2, 3]

Ordered list of any BSON values

Binary data

BinData(0, "...")

Raw bytes — files, hashes, encrypted blobs

ObjectId

ObjectId("64f1a2b3...")

12-byte unique identifier, default _id type

Boolean

true / false

Date

ISODate("2024-01-15")

Milliseconds since Unix epoch, UTC

Null

null

Explicit "no value" — distinct from a missing field

32-bit integer

NumberInt(42)

Whole numbers that fit in 4 bytes

Timestamp

Timestamp(1690000000, 1)

Internal — used by the oplog, not app data

64-bit integer

NumberLong(42)

Whole numbers that fit in 8 bytes

Decimal128

NumberDecimal("9.99")

Exact base-10 precision — use for money

Regular Expression

/^abc/i

Stored pattern, usable in queries

Type Numbers and Aliases

Every BSON type has both a numeric code and a string alias. The $type query operator accepts either form, which is useful when auditing a collection for inconsistent field types.

Type codes and aliases

JS
// 1  = "double"        8  = "bool"           18 = "long"
// 2  = "string"        9  = "date"           19 = "decimal"
// 3  = "object"        10 = "null"           127 = "maxKey"
// 4  = "array"         11 = "regex"          -1  = "minKey"
// 5  = "binData"       16 = "int"
// 7  = "objectId"      17 = "timestamp"

// Find documents where "price" was mistakenly stored as a string
db.products.find({ price: { $type: "string" } })

// Same query using the numeric code instead of the alias
db.products.find({ price: { $type: 2 } })

// "number" is a special alias that matches double, int, long, AND decimal
db.products.find({ price: { $type: "number" } })
Inspecting BSON Types in mongosh

Distinguishing look-alike values

JS
db.events.insertMany([
  { label: "A", when: new Date() },          // BSON Date
  { label: "B", when: "2024-01-15" },        // plain string — NOT a Date!
  { label: "C", count: 10 },                 // Double (mongosh default)
  { label: "D", count: NumberInt(10) },      // 32-bit integer
  { label: "E", count: NumberLong(10) }      // 64-bit integer
])

// This query only matches documents where "when" is a real BSON Date
db.events.find({ when: { $type: "date" } })
// → returns only document "A"
Warning
A date typed as a plain string ("2024-01-15") sorts and compares lexicographically, not chronologically, and will not match $type: "date" queries or date-range queries. Always insert dates through your driver's native date type or new Date() / ISODate() in mongosh.
Size Considerations
  • A single document is capped at 16 MB of BSON — this is the format's practical limit, not an arbitrary MongoDB rule.

  • Binary data (BinData) is base64-encoded when displayed in JSON tools like mongoexport, which inflates its apparent size by roughly 33% — the actual BSON storage is the raw byte count.

  • Field names count toward document size on every single document — extremely verbose key names across millions of documents add up. Short, consistent field names save real storage.

  • Use Object.bsonsize(doc) in mongosh to measure the exact BSON byte size of any document you have in hand.

Tip
When exporting or inspecting data outside mongosh, mongoexport converts BSON to Extended JSON — a text JSON representation that wraps non-JSON-native types in tagged objects, e.g. { "$oid": "64f1a2b3..." } for an ObjectId. This lets you round-trip BSON through plain-text tooling without losing type information.