MongoDB Best Practices
A checklist-style tour of the habits that separate a MongoDB deployment that scales smoothly from one that falls over under load. Most of these are cross-references to deeper pages — this is the "did I remember to" summary.
1. Design Schema for Access Patterns, Not Entities
Start from your application's queries, not from an ER diagram. Ask "what does the most frequent query need to read in one go?" before deciding what to embed and what to reference. See the Embedding vs Referencing and Schema Design Patterns pages.
2. Always Index the Fields You Query On
// If this runs often...
db.orders.find({ customerId: id, status: "shipped" }).sort({ createdAt: -1 })
// ...this index should exist:
db.orders.createIndex({ customerId: 1, status: 1, createdAt: -1 })COLLSCAN) — it gets slower every day as the collection grows. Use .explain("executionStats") to check for COLLSCAN on any query you expect to run often.3. Follow the ESR Rule for Compound Indexes
Order compound index fields as Equality, Sort, Range — equality-matched fields first, then fields you sort by, then range-filtered fields last. This lets MongoDB use the index for the widest variety of matching queries.
// Query: find shipped orders for a customer, newest first, placed
// in the last 30 days
db.orders.find({
customerId: id, // Equality
status: "shipped", // Equality
createdAt: { $gte: thirtyDaysAgo } // Range
}).sort({ createdAt: -1 }) // Sort
db.orders.createIndex({ customerId: 1, status: 1, createdAt: -1 })
// customerId + status = Equality, createdAt = Sort/Range combined4. Size Your Connection Pool Deliberately
Create one
MongoClientper process/application instance and let it manage pooling — never open a new client per request.Set maxPoolSize based on expected concurrency, not an arbitrary large number — an oversized pool just moves the bottleneck to the server's connection limit.
In serverless environments, reuse the client across invocations (module-level singleton) instead of connecting on every cold path.
5. Use writeConcern: majority for Durable Writes
db.orders.insertOne(doc, { writeConcern: { w: "majority" } })
// Waits for acknowledgment from a majority of replica set members —
// the write survives a primary failover. See the Read/Write Concerns page.6. Enable Retryable Writes
Retryable writes (on by default with modern drivers via retryWrites=true in the connection string) automatically retry a write once if it fails due to a transient network error or replica set election — without this, a failover during a write could otherwise surface as an application error for something that would have succeeded on retry.
7. Avoid Unbounded Arrays
An array field with no natural cap (comments, log entries, notifications) will eventually hit the 16MB document limit and cause expensive document rewrites well before that. Cap it, bucket it, or move it to a referenced collection. See One-to-Many and Schema Design Patterns.
8. Project Only What You Need
// Instead of pulling the whole document over the wire...
db.products.find({ category: "electronics" })
// ...limit the payload to what the UI actually renders
db.products.find({ category: "electronics" }, { name: 1, price: 1, thumbnailUrl: 1 })9. Monitor the Basics
Metric | Why it matters |
|---|---|
opcounters (insert/query/update/delete rate) | Baseline load — spot unexpected spikes |
connections (current / available) | Approaching the connection limit means requests will start failing |
queues / tickets (WiredTiger) | Requests waiting for a storage engine ticket — a sign of I/O contention |
replication lag | Secondary falling behind risks stale reads and slow failover |
index hit ratio / COLLSCAN count | Rising unindexed scans predict future slowdowns |
cache eviction rate (WiredTiger) | Working set no longer fits in RAM — a leading indicator to scale up |
10. Security Checklist
Enable authentication — never run a production
mongodwith--noauthor expose an unauthenticated instance to the network.Use least-privilege custom roles per application instead of granting
root/dbOwnerbroadly. See Authorization.Enable TLS for all client and inter-node traffic. See Encryption.
Restrict network access with IP allowlists / VPC peering — never bind to 0.0.0.0 on a publicly reachable host without a firewall.
Rotate credentials and use a secrets manager, not hardcoded connection strings.
Enable encryption at rest, and use Client-Side Field Level Encryption or Queryable Encryption for especially sensitive fields (SSNs, payment data).
Keep MongoDB server and driver versions patched — subscribe to MongoDB security advisories.