MongoDB Atlas Setup
MongoDB Atlas is the cloud-hosted MongoDB service. Here is the step-by-step setup:
- Go to https://cloud.mongodb.com and sign up for a free account
- Create a new Project (e.g., "MyBackend")
- Create a Cluster — choose the free tier (M0 Sandbox)
- Go to Database Access → Add a database user with a strong username and password
- Go to Network Access → Add IP Address:
- For development: add your current IP or
0.0.0.0/0(allow all — only in dev!) - For production: add only your server's IP address
- Go to Connect → Drivers → Copy the connection string:
- Replace
<password>with your actual password andmyDatabaseNamewith your DB name
mongodb+srv://username:password@cluster0.xxxxx.mongodb.net/myDatabaseName
---
mongoose.connect() — All Options Explained
await mongoose.connect(process.env.MONGODB_URI, {
dbName: 'myapp', // Use this specific database
serverSelectionTimeoutMS: 5000, // Wait 5s before failing
socketTimeoutMS: 45000, // Close sockets after 45s inactivity
maxPoolSize: 10, // Max concurrent connections in pool
minPoolSize: 2, // Keep min 2 connections alive
connectTimeoutMS: 10000, // Initial connection timeout
heartbeatFrequencyMS: 10000, // How often to check server health
});
Since Mongoose 6.x,useNewUrlParseranduseUnifiedTopologyoptions are no longer needed — they are the default. Passing them causes a deprecation warning.
---
Connection Events
Mongoose emits events that you can listen to for monitoring and debugging:
mongoose.connection.on('connected', () => {
console.log('✅ MongoDB connected');
});
mongoose.connection.on('error', (err) => {
console.error('❌ MongoDB connection error:', err);
});
mongoose.connection.on('disconnected', () => {
console.warn('⚠️ MongoDB disconnected');
});
mongoose.connection.on('reconnected', () => {
console.log('🔄 MongoDB reconnected');
});
---
Retry Logic
If the database connection fails on startup (network issue, wrong credentials, Atlas IP whitelist), you should retry instead of crashing:
const connectWithRetry = async (retries = 5, delay = 5000) => {
for (let i = 0; i < retries; i++) {
try {
await mongoose.connect(process.env.MONGODB_URI);
console.log('✅ DB connected');
return;
} catch (err) {
console.error(`Attempt ${i + 1} failed: ${err.message}`);
if (i < retries - 1) {
console.log(`Retrying in ${delay / 1000}s...`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
console.error('All connection attempts failed. Exiting.');
process.exit(1);
};
---
Common Errors and Solutions
| Error | Cause | Solution |
|---|---|---|
Authentication failed | Wrong username/password in URI | Double-check Atlas Database Access credentials |
network timeout | Atlas IP whitelist blocks your IP | Add your IP in Network Access |
querySrv ENOTFOUND | No internet or wrong cluster URL | Check internet, verify URI from Atlas dashboard |
serverSelectionTimeoutMS expired | DB unreachable within timeout | Increase timeout or check network |
MongoParseError: URI malformed | Missing database name in URI | Ensure URI ends with /dbName before ? |
buffering timed out | Query executed before connection | Always await connectDB() before app.listen() |
---
Mongoose Debug Mode
Turn on query logging for development debugging:
if (process.env.NODE_ENV === 'development') {
mongoose.set('debug', true);
// Logs every Mongoose operation to console:
// Mongoose: users.findOne({ email: 'test@test.com' }) {}
}
---
Connection Pooling
Mongoose maintains a connection pool — a set of pre-established connections that are reused for incoming queries. This avoids the overhead of creating a new TCP connection for every database operation. The maxPoolSize (default 5) controls how many concurrent connections are kept.
In a high-traffic production app, increasing maxPoolSize to 10-20 can improve throughput. In serverless environments (AWS Lambda, Vercel), set it to 1 and use the mongoose-legacy-pluralize pattern to reuse connections across invocations.
---
Checking Connection State
// mongoose.connection.readyState values:
// 0 = disconnected
// 1 = connected
// 2 = connecting
// 3 = disconnecting
const state = mongoose.connection.readyState;
console.log('Connection state:', state === 1 ? 'connected' : 'not connected');
---
Graceful Shutdown
When your server receives a SIGTERM (e.g., from PM2 or Kubernetes), close the MongoDB connection cleanly:
process.on('SIGTERM', async () => {
console.log('SIGTERM received. Closing connections...');
await mongoose.connection.close();
server.close(() => {
console.log('Server closed gracefully');
process.exit(0);
});
});