Skip to content
SunnyWriteUps
Go back

MongoDB from Development to Production A Complete Guide with Best Practices

Edit page

Many developers start with a local MongoDB instance and carry the same setup into production. This often leads to performance bottlenecks, security vulnerabilities, and maintenance challenges.

In this guide, we’ll cover everything you need to know about using MongoDB—from getting started to deploying a production-ready database with best practices.


What is MongoDB?

MongoDB is a document-oriented NoSQL database that stores data as BSON (Binary JSON) documents instead of traditional rows and tables.

Example document:

{
  "_id": "665e7c4d8d8e",
  "name": "John Doe",
  "email": "john@example.com",
  "age": 29,
  "skills": [
    "Node.js",
    "MongoDB",
    "Docker"
  ]
}

Unlike SQL databases, every document can have a different structure, making schema evolution much easier.


Installing MongoDB

For local development, you can:

Docker example:

docker run -d \
  --name mongodb \
  -p 27017:27017 \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=password \
  mongo:8

Connect using:

mongodb://admin:password@localhost:27017

Choosing a Schema

Although MongoDB is schema-less, your application shouldn’t be.

Bad example:

{
  "username": "john"
}
{
  "name": "John Doe",
  "email": "john@example.com",
  "address": {
    "city": "London"
  }
}

Different document structures make querying difficult.

Instead, define a consistent schema using Mongoose or MongoDB Schema Validation.

Example:

const UserSchema = new Schema({
    name: String,
    email: String,
    age: Number
});

Embed vs Reference

This is one of the biggest design decisions.

Embed

{
    "title": "MongoDB Guide",
    "comments": [
        {
            "user": "John",
            "text": "Great article!"
        }
    ]
}

Use embedding when:


Reference

{
    "title": "MongoDB Guide",
    "authorId": ObjectId("...")
}

Use references when:


Indexing

Without indexes:

Query


Collection Scan



Every Document

With indexes:

Query



Index



Matching Documents

Example:

db.users.createIndex({
    email: 1
});

Compound Index:

db.orders.createIndex({
    customerId: 1,
    createdAt: -1
});

Text Index:

db.posts.createIndex({
    title: "text",
    description: "text"
});

TTL Index:

db.sessions.createIndex(
{
    expiresAt: 1
},
{
    expireAfterSeconds: 0
});

Useful for sessions, OTPs, temporary tokens, and logs.


Query Optimization

Avoid:

db.users.find()

Better:

db.users.find(
{
    status: "ACTIVE"
})
.limit(20)
.project({
    name:1,
    email:1
})

Always:


Pagination

Bad:

.skip(100000)
.limit(20)

This becomes slower as data grows.

Better:

.find({
    _id: {
        $gt: lastId
    }
})
.limit(20)

Cursor-based pagination is much faster.


Aggregation Pipeline

Instead of multiple queries:

const users = ...
const orders = ...
const payments = ...

Use Aggregation:

db.orders.aggregate([
{
    $match:{
        status:"PAID"
    }
},
{
    $group:{
        _id:"$customerId",
        total:{
            $sum:"$amount"
        }
    }
}
])

Benefits:


Connection Pooling

Don’t create a new connection for every request.

Bad:

app.get("/", async () => {
    await mongoose.connect(...)
});

Good:

mongoose.connect(process.env.MONGO_URI);

Let the driver manage the connection pool.


Transactions

Use transactions only when necessary.

Example:

const session = await mongoose.startSession();

session.startTransaction();

try{

// update balance

// create order

await session.commitTransaction();

}catch(err){

await session.abortTransaction();

}

Transactions add overhead, so avoid using them for every write.


Security Best Practices

Never expose MongoDB publicly.

Enable:

Never use:

mongodb://root:password@database

Store credentials in environment variables.

MONGO_URI=...

Backup Strategy

Always have backups.

Recommended:

Remember:

A backup is useless unless you’ve successfully restored it.


Replica Sets

Production databases should never run on a single node.

Replica Set:

Primary



├── Secondary



└── Secondary

Benefits:


Sharding

When a single server isn’t enough:

Application



Router



Shard 1

Shard 2

Shard 3

Choose shard keys carefully.

Avoid:

Prefer high-cardinality fields.


Monitoring

Track:

Enable the profiler for slow queries:

db.setProfilingLevel(1, {
    slowms: 100
});

Logging

Monitor:

Centralize logs using:


Data Validation

MongoDB supports schema validation.

Example:

db.createCollection("users",{
validator:{
$jsonSchema:{
required:[
"name",
"email"
]
}
}
});

This prevents invalid documents from entering your database.


Common Mistakes

❌ No indexes

❌ Huge documents

❌ Unlimited arrays

❌ Storing binary files inside MongoDB

❌ Creating unnecessary collections

❌ Using skip() for large pagination

❌ Exposing MongoDB to the internet

❌ Running without backups


Production Checklist

Before going live, ensure you have:


Final Thoughts

MongoDB is incredibly powerful when used correctly. While it’s easy to get started with flexible schemas and rapid development, long-term success depends on thoughtful schema design, efficient indexing, secure deployments, and continuous monitoring.

A production-ready MongoDB deployment is more than just storing documents—it requires planning for scale, resilience, performance, and security from day one.

By following the practices outlined in this guide, you’ll be well-equipped to build MongoDB applications that remain fast, reliable, and maintainable as your data and user base grow.


Edit page
Share this post on:

Previous Post
Building Stateful AI Agents with LangGraph and TypeScript
Next Post
How would you architect a large Angular app for dynamic module loading, lazy loading, and role-based access?