Connecting to MongoDB cluster from NextJS app hosted on Vercel

I am building a NextJS web app hosted on Vercel. One of my api routes contains the following code to connect to my cluster:

const {MongoClient} = require('mongodb');


// connect to client
const uri = process.env.URI
const client = await MongoClient.connect(uri, {useNewUrlParser: true, useUnifiedTopology: true}) // this line hangs on Vercel

const companies = client.db("myDatabase").collection("companies");

// update document    
const updateDoc = {$set: set};
const result = await companies.updateOne(filter, updateDoc)
console.log(`${result.matchedCount} document(s) matched the filter, updated ${result.modifiedCount} document(s): `, updateDoc);

// close connection to client    
await client.close();

This runs fine on localhost. However, when running on Vercel, the code hangs on the MongoClient.connect() line. There are no errors but the connection doesn’t resolve.

I have whitelisted all IP addresses in Network Access in Atlas (“Allow Access from anywhere”) as I’ve seen that Vercel does not have a particular IP address but still getting the same issue.

Any idea what could be causing the issue?

The code in general is correct - if you are using the 4.x driver you can remove the useNewUrlParser and userUnifiedTopology options from the connect call. I would double check the URI env variable is correct and that the function can actually reach the cluster. Also it’s usually best to cache the connected client in the initialization phase as we describe here: https://www.mongodb.com/docs/atlas/best-practices-connecting-from-vercel/. I’d also check the default timeout of the function and maybe it needs more time for the connection phase. Another thing to potentially help debug is to listen to the monitor heartbeats and see if there is a potential issue there.

const client = new MongoClient(uri);
client.on('serverHeartbeatStarted', (event) => {
  console.log(event);
});
client.on('serverHeartbeatSucceeded', (event) => {
  console.log(event);
});
client.on('serverHeartbeatFailed', (event) => {
  console.log(event);
});
await client.connect();

Hi @Durran_Jordan, thanks for your reply!

I’ve doubled checked the uri and it looks like this (with my username and password):

mongodb+srv://<username>:<password>@cluster0.2xyeu.mongodb.net/?retryWrites=true&w=majority

It’s the same uri I used from my localhost and I was able to connect fine from there so I don’t think that’d be the issue.

I’ve added the 3 monitor heartbeats listeners in my code. I get the following console logs:

ServerHeartbeatStartedEvent {
  connectionId: 'cluster0-shard-00-02.2xyeu.mongodb.net:27017'
}
ServerHeartbeatStartedEvent {
  connectionId: 'cluster0-shard-00-00.2xyeu.mongodb.net:27017'
}
ServerHeartbeatStartedEvent {
  connectionId: 'cluster0-shard-00-01.2xyeu.mongodb.net:27017'
}

I also sometimes see this error popping up:

ules/mongodb/lib/utils.js:587:9)
}
2022-06-05T10:02:01.926Z	dc5eee5e-9613-42b7-8193-9035eaff8971	ERROR	MongoServerSelectionError: Server selection timed out after 30000 ms
    at Timeout._onTimeout (/var/task/node_modules/mongodb/lib/sdam/topology.js:312:38)
    at listOnTimeout (internal/timers.js:557:17)
    at processTimers (internal/timers.js:500:7) {
  reason: TopologyDescription {
    type: 'ReplicaSetNoPrimary',
    servers: Map(3) {
      'cluster0-shard-00-00.2xyeu.mongodb.net:27017' => [ServerDescription],
      'cluster0-shard-00-01.2xyeu.mongodb.net:27017' => [ServerDescription],
      'cluster0-shard-00-02.2xyeu.mongodb.net:27017' => [ServerDescription]
    },
    stale: false,
    compatible: true,
    heartbeatFrequencyMS: 10000,
    localThresholdMS: 15,
    setName: 'atlas-c5yrqw-shard-0',
    logicalSessionTimeoutMinutes: undefined
  }
}

Does this Timeout message shed any light on the cause of the issue?

Many thanks for your help!

@Durran_Jordan are you able to help at all?

Since my last message, I’ve implemented the new Vercel integration but I’m experiencing the same issue. The MONGODB_URI produced automatically through the integration looks fine, but the connection hangs on await client.connect().

I’ve been stuck on this for months now and would really appreciate some help in identifying where the issue may come from!

Many thanks in advance!

Have you tried using this tutorial. [How to Integrate MongoDB Into Your Next.js App | MongoDB](https://How to Integrate MongoDB Into Your Next.js App) There is file that makes the connection to the atlas and makes the cache.

Good Luck.

Hey, I’m experiencing the same exact problem on the same exact place.

The weird thing in my case is that when I’m doing actions on my Front End that trigger a DB update, the connection is working perfect, I only have a DB connection problem when receiving Stripe’s events to my webhooks endpoint, and trying to connect to Mongo and update my DB.

I have tried Vercel’s Mongo integration, and all the tutorials above, same problem every time.

If anyone knows a solution for this problem, please help. :pray:t3:

Hey @Laekipia , @Durran_Jordan, is there any solution for this problem?

Were you able to resolve this issue?

Vercel is serverless. Meaning that for each user that connects, they spin up a vm and kill it when the request is done (or 30 seconds). This means that your connect is not persisting to your pages.

Here’s my solution: <<see code below>>

Then you can make mongo calls with await mongoDb.collection(‘birds’, c=>c.findAll({}).toArray());

It works for form actions, but not for server actions. Will post a solution for server actions when I can find it.

It works for server actions. I just had a different database for localhost and vercel so my values weren’t being saved. Made the same edits in vercel hosted app and now they show up :+1:


class MongoDBClass {
  uri: string;

  constructor(uri: string | undefined) {
    if (!uri) throw new Error("MONGODB_URI is not set in env.");
    this.uri = uri;
  }

  connect() {
    const client = new MongoClient(this.uri);
    return client.connect().then(() => {
      return client;
    });
  }

  command<ReturnType>(callback: (client: MongoClient) => Promise<ReturnType>) {
    let cmdClient: MongoClient;

    return this.connect()
      .then((client) => {
        cmdClient = client;

        return callback(client);
      })
      .finally(() => {
        cmdClient.close();
      });
  }

  collection<ReturnType, T extends Document = Document>(
    collectionName: string,
    callback: (collection: Collection<T>) => Promise<ReturnType>
  ) {
    return this.command<ReturnType>((client) => {
      const collection = client.db().collection<T>(collectionName);

      return callback(collection);
    });
  }
}

export const mongoDb = new MongoDBClass(process.env.MONGODB_URI);