How to fix MongoTopologyClosedError: Topology is closed in MongoDB
This error occurs when attempting database operations after the MongoDB client connection has been closed or when the topology (internal connection manager) was terminated. The most common cause is closing the client prematurely or attempting operations on a stale connection.
Quick fix
Fixes MongoTopologyClosedError: Topology is closed
const { MongoClient } = require('mongodb');
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
const database = client.db('myDatabase');
const collection = database.collection('myCollection');
// ✅ Await ALL operations
const result = await collection.findOne({ name: 'test' });
await collection.insertOne({ name: 'example', value: 123 });
console.log('Operations completed:', result);
} finally {
// Only close after operations finish
await client.close();
}
}
run().catch(console.error);- Ensure operations complete before closing connection
- Use singleton pattern for long-lived applications
- Implement singleton pattern for serverless functions
- Never reuse a closed client
const { MongoClient } = require('mongodb');const client = new MongoClient(uri);async function run() {try {await client.connect();const database = client.db('myDatabase');const collection = database.collection('myCollection');// ✅ Await ALL operationsconst result = await collection.findOne({ name: 'test' });await collection.insertOne({ name: 'example', value: 123 });console.log('Operations completed:', result);} finally {// Only close after operations finishawait client.close();}}run().catch(console.error);MongoTopologyClosedError: Topology is closed
What this error means
The MongoTopologyClosedError is thrown when you try to perform database operations on a MongoDB client whose topology has been closed. The "topology" refers to MongoDB's internal connection management system that handles connections to replica sets, sharded clusters, or standalone servers. This error typically indicates that client.close() was called (either explicitly or implicitly) while operations were still pending, or that you're attempting to reuse a closed client connection. Once a MongoDB client is closed, its topology is destroyed and cannot be reused—you must create a new client instance. In serverless environments (Lambda, Vercel), this error commonly occurs when connections are not properly managed using singleton patterns, or when the connection pool is exhausted due to improper connection lifecycle management.
Typical symptoms
- Database operations fail with "Topology is closed" error
- Error appears after client.close() was called
- Operations work initially but fail after some time
- Intermittent failures in serverless functions
- Application becomes unresponsive after database reconnection attempts
- Error occurs when reusing a closed MongoClient instance
- Connection errors after long idle periods
Common causes
- Calling client.close() in a finally block before async operations complete
- Attempting to reuse a MongoClient instance after calling close()
- Not using singleton pattern in serverless functions
- Connection timing out or being dropped by the server
- Multiple close() calls on the same client
- Accessing database after application shutdown sequence started
- Connection pool exhaustion in high-concurrency scenarios
- Framework migration issues (e.g., Meteor 3 upgrade)
How to fix "MongoTopologyClosedError: Topology is closed"
The most critical fix is to await all operations before closing the client:
const { MongoClient } = require('mongodb');
const client = new MongoClient(uri);
async function run() {
try {
await client.connect();
const database = client.db('myDatabase');
const collection = database.collection('myCollection');
// ✅ Await ALL operations
const result = await collection.findOne({ name: 'test' });
await collection.insertOne({ name: 'example', value: 123 });
console.log('Operations completed:', result);
} finally {
// Only close after operations finish
await client.close();
}
}
run().catch(console.error);Do not close the client while operations are still running.
In Express, Next.js, or other long-running applications, keep one connection open:
// lib/mongodb.js
const { MongoClient } = require('mongodb');
const uri = process.env.MONGODB_URI;
const options = {};
let client;
let clientPromise;
if (!process.env.MONGODB_URI) {
throw new Error('Please add your MongoDB URI to .env.local');
}
if (process.env.NODE_ENV === 'development') {
// In development mode, use a global variable to preserve client across HMR
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
// In production mode, create a new client
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
module.exports = clientPromise;// Usage in API routes or pages
const clientPromise = require('./lib/mongodb');
async function getUsers() {
const client = await clientPromise;
const db = client.db('myDatabase');
return db.collection('users').find().toArray();
}This keeps the connection alive and prevents topology closure.
For AWS Lambda, Vercel, or other serverless platforms, use module-level caching:
const { MongoClient } = require('mongodb');
const uri = process.env.MONGODB_URI;
let cachedClient = null;
async function connectToDatabase() {
if (cachedClient) {
return cachedClient;
}
const client = new MongoClient(uri, {
maxPoolSize: 10,
minPoolSize: 1,
maxIdleTimeMS: 120000, // 2 minutes
});
await client.connect();
cachedClient = client;
return client;
}
// Lambda handler
exports.handler = async (event) => {
const client = await connectToDatabase();
const db = client.db('myDatabase');
const result = await db.collection('data').findOne({ id: event.id });
// ⚠️ Do NOT close in serverless - reuse connection
// await client.close(); // ❌ WRONG
return {
statusCode: 200,
body: JSON.stringify(result),
};
};The connection is reused across invocations within the same function instance.
Create a new client instance if you need to reconnect after closing:
const { MongoClient } = require('mongodb');
let client = null;
async function getClient() {
// Check if client exists and is connected
if (client && client.topology && client.topology.isConnected()) {
return client;
}
// Create new client if needed
client = new MongoClient(uri);
await client.connect();
return client;
}
// Usage
async function performOperation() {
const currentClient = await getClient();
const db = currentClient.db('myDatabase');
return db.collection('data').find().toArray();
}
// Graceful shutdown
async function shutdown() {
if (client) {
await client.close();
client = null; // ✅ Set to null so new client is created next time
}
}
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);Adjust connection settings to prevent premature closures:
const { MongoClient } = require('mongodb');
const client = new MongoClient(uri, {
maxPoolSize: 50,
minPoolSize: 5,
maxIdleTimeMS: 300000, // 5 minutes
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
connectTimeoutMS: 10000,
});
await client.connect();
// Monitor topology events
client.on('topologyClosed', () => {
console.error('MongoDB topology closed unexpectedly');
});
client.on('close', () => {
console.log('MongoDB connection closed');
});
client.on('error', (error) => {
console.error('MongoDB client error:', error);
});These settings help maintain stable connections and provide visibility into topology state.
Advanced notes
Cannot Reuse After Close: After calling client.close(), the MongoClient instance is permanently destroyed and cannot be reconnected. The official MongoDB documentation states this is by design—you must create a new client instance if you need to reconnect.
Serverless Connection Leaks: Some serverless platforms can leak connections when functions are suspended. The real issue isn't the number of connections during normal operation, but that connections may not be properly cleaned up when execution contexts freeze. The singleton pattern mitigates this by reusing connections across warm starts.
maxIdleTimeMS Tuning: For serverless environments, set maxIdleTimeMS to match your platform's timeout limit (15 minutes for Lambda, 10 seconds for Vercel). This prevents connections from staying open longer than the execution context.
Mongoose Alternative: If using Mongoose, it handles connection state internally with built-in reconnection logic. Use mongoose.connection.readyState to check connection status (0=disconnected, 1=connected, 2=connecting, 3=disconnecting).
Calling close() vs Not Calling It: In Node.js driver documentation, calling close() does not terminate all connections immediately if operations are still running—it waits for pending operations to complete. However, there is only one JavaScript thread executing, so for long-running applications, it's better to keep connections open for the application's lifetime rather than repeatedly opening and closing them.
Meteor 3 Migration: Users migrating to Meteor 3 reported MongoTopologyClosedError at startup due to framework changes in connection handling. Solutions involved updating connection configuration and ensuring proper initialization sequencing.
Frequently asked questions
- What does "MongoTopologyClosedError: Topology is closed" mean?
- The MongoTopologyClosedError is thrown when you try to perform database operations on a MongoDB client whose topology has been closed. The "topology" refers to MongoDB's internal connection management system that handles connections to replica sets, sharded clusters, or standalone servers. close() was called (either explicitly or implicitly) while operations were still pending, or that you're attempting to reuse a closed client connection.
- How do I fix "MongoTopologyClosedError: Topology is closed"?
- This error occurs when attempting database operations after the MongoDB client connection has been closed or when the topology (internal connection manager) was terminated. The most common cause is closing the client prematurely or attempting operations on a stale connection.
- What causes "MongoTopologyClosedError: Topology is closed"?
- Calling client.close() in a finally block before async operations complete Attempting to reuse a MongoClient instance after calling close() Not using singleton pattern in serverless functions
- Is the "MongoTopologyClosedError: Topology is closed" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚MongoDB Official Documentation
- 📖mongodb.com - 148523(Official Docs)
- 🔗
- 🐙github.com - 12229(GitHub)
- 📖mongodb.com - 11507(Official Docs)
- 🔗
- 📖mongoosejs.com - connections(Official Docs)
- 📖mongodb.com - connection troubleshooting(Official Docs)