Script Valley
MongoDB: Complete Course
Production MongoDB: Transactions, Replication, and SecurityLesson 6.4

MongoDB connection pooling and performance tuning in Node.js

connection pool, maxPoolSize, minPoolSize, MongoClient singleton pattern, serverSelectionTimeoutMS, socketTimeoutMS, connection string options, pool monitoring

Why connection pooling matters

MongoDB connection pool

Establishing a new MongoDB TCP connection takes 20–100 ms and allocates resources on both the client and server. Under load, creating a connection per request would saturate MongoDB's connection limit within seconds. The MongoClient maintains a pool of pre-established, reusable connections — each request borrows one for its operation and immediately returns it, with minimal overhead after pool warm-up.

// WRONG — new connection per request, pools bypassed entirely
app.get('/products', async (req, res) => {
  const client = new MongoClient(uri)  // new TCP connection every time
  await client.connect()
  const data = await client.db('shop').collection('products').find().toArray()
  await client.close()
  res.json(data)
})

// CORRECT — singleton client created at startup, shared across all requests
let _db = null
export async function getDB() {
  if (_db) return _db
  const client = await MongoClient.connect(process.env.MONGO_URI, {
    maxPoolSize: 10,               // max concurrent connections
    minPoolSize: 2,                // keep 2 alive to reduce cold-start latency
    serverSelectionTimeoutMS: 5000,
    socketTimeoutMS: 45000
  })
  _db = client.db('shopDB')
  return _db
}

app.get('/products', async (req, res) => {
  const db = await getDB()  // instant — returns cached db reference
  res.json(await db.collection('products').find().toArray())
})

Start with maxPoolSize: 10. Increase it only after profiling shows requests are waiting in the pool queue under real production load.

Up next

How to back up and restore MongoDB databases in production

Sign in to track progress