The rules below are enforced by the server, not the driver, so you find out at write time.
| Rule | Limit |
|---|---|
| BSON document size | 16 MiB (16,777,216 bytes) |
| Nesting depth | 100 levels; each object or array counts |
| Database name | under 64 bytes |
| Namespace db.collection | 255 bytes, or 235 bytes when sharded |
| Indexes per collection | 64, at most 32 fields in one compound index |
| Field names | may not contain the null character |
The 16 MiB ceiling shapes designs: it exists so a document always fits in memory and on the wire without streaming, and it covers pipeline output as well as stored documents.
import { calculateObjectSize, serialize, Binary } from 'bson';
const LIMIT = 16 * 1024 * 1024;
console.log('over limit :', serialize({ blob: new Binary(Buffer.alloc(LIMIT)) }).length);
const short = {}, long = {};
for (let i = 0; i < 1000; i++) { short['v' + i] = 20.5; long['measured' + i] = 20.5; }
console.log('short names :', calculateObjectSize(short), '| long names :',
calculateObjectSize(long));over limit : 16777232 short names : 13895 | long names : 20895
The first line is the warning: the bson library happily serialized a document larger than 16 MiB. Nothing client-side stops you — the server returns BSONObjectTooLarge when the write arrives. Check sizes yourself with calculateObjectSize, or Object.bsonsize(doc) in mongosh 403 .
Field names are stored in full in every document, which is what the second line measures: the same 1,000 values cost 13,895 bytes named v0-style and 20,895 named measured0-style, half as much again. Across hundreds of millions of documents that is real money, and it is why time series collections (Time Series Collections) store measurements differently. Elsewhere readable names win — but never repeat the collection name in a field (bookTitle inside books).
Since MongoDB 5.0 the server stores field names containing . and $, so a document scraped from an external API need not be mangled on the way in; querying them needs $getField and $setField, which makes the support an escape hatch rather than a naming style.