How to fix MongoTopologyClosedError: Topology is closed in MongoDB

MongoDBINTERMEDIATEHIGHUpdated Dec 22, 2025· 159 views

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);
  1. Ensure operations complete before closing connection
  2. Use singleton pattern for long-lived applications
  3. Implement singleton pattern for serverless functions
  4. Never reuse a closed client
mongodb — error
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);
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

  1. Calling client.close() in a finally block before async operations complete
  2. Attempting to reuse a MongoClient instance after calling close()
  3. Not using singleton pattern in serverless functions
  4. Connection timing out or being dropped by the server
  5. Multiple close() calls on the same client
  6. Accessing database after application shutdown sequence started
  7. Connection pool exhaustion in high-concurrency scenarios
  8. Framework migration issues (e.g., Meteor 3 upgrade)

How to fix "MongoTopologyClosedError: Topology is closed"

1Ensure operations complete before closing connection

The most critical fix is to await all operations before closing the client:

javascript
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.

2Use singleton pattern for long-lived applications

In Express, Next.js, or other long-running applications, keep one connection open:

javascript
// 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;
javascript
// 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.

3Implement singleton pattern for serverless functions

For AWS Lambda, Vercel, or other serverless platforms, use module-level caching:

javascript
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.

4Never reuse a closed client

Create a new client instance if you need to reconnect after closing:

javascript
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);
5Configure connection timeout and pooling

Adjust connection settings to prevent premature closures:

javascript
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