Skip to content

Next.js + MongoDB Connection Storming

Next.js + MongoDB Connection Storming

Building a Next.js application connected to MongoDB can feel like a match made in heaven. MongoDB stores all of its data as JSON objects, which don’t require transformation into JavaScript objects like relational SQL data does. However, when deploying your application to a serverless production environment such as Vercel, it is crucial to manage your database connections properly.

If you encounter errors like these, you may be experiencing Connection Storming:

  • MongoServerSelectionError: connect ECONNREFUSED <IP_ADDRESS>:<PORT>
  • MongoNetworkError: failed to connect to server [<hostname>:<port>] on first connect
  • MongoTimeoutError: Server selection timed out after <x> ms
  • MongoTopologyClosedError: Topology is closed, please connect
  • Mongo Atlas: Connections % of configured limit has gone above 80

Connection storming occurs when your application has to mount a connection to Mongo for every serverless function or API endpoint call. Vercel executes your application’s code in a highly concurrent and isolated fashion. So, if you create new database connections on each request, your app might quickly exceed the connection limit of your database.

We can leverage Vercel’s fluid compute model to keep our database connection objects warm across function invocations. Traditional serverless architecture was designed for quick, stateless web app transactions. Now, especially with the rise of LLM-oriented applications built with Next.js, interactions with applications are becoming more sequential. We just need to ensure that we assign our MongoDB connection to a global variable.

unnamed

Protip: Use global variables

Vercel’s fluid compute model means all memory, including global constants like a MongoDB client, stays initialized between requests as long as the instance remains active. By assigning your MongoDB client to a global constant, you avoid redundant setup work and reduce the overhead of cold starts. This enables a more efficient approach to reusing connections for your application’s MongoDB client.

The example below demonstrates how to retrieve an array of users from the users collection in MongoDB and either return them through an API request to /api/users or render them as an HTML list at the /users route. To support this, we initialize a global clientPromise variable that maintains the MongoDB connection across warm serverless executions, avoiding re-initialization on every request.

// lib/mongodb.ts
import { MongoClient, Db } from 'mongodb';

if (!process.env.MONGODB_URI) {
  throw new Error('Invalid/Missing environment variable: "MONGODB_URI"');
}

const clientPromise: Promise<MongoClient> = (async () => {
  const client = new MongoClient(process.env.MONGODB_URI!);
  const connectedClient = await client.connect();
  console.log('✅ MongoDB connection established');
  return connectedClient;
})();

export async function getDatabase(): Promise<Db> {
  const client = await clientPromise;
  return client.db('testing_db');
}

Using this database connection in your API route code is easy:

// src/app/api/users/route.ts
import { NextResponse } from 'next/server';
import { getDatabase } from '@/lib/mongodb';

export async function GET() {
  const db = await getDatabase();
  const collection = db.collection('users');
  const users = await collection.find({}).toArray();
  return NextResponse.json({ users });
}

You can also use this database connection in your server-side rendered React components.

// src/app/users/page.tsx
import { getDatabase } from '@/lib/mongodb'

export default async function UserList() {
  const db = await getDatabase()
  const collection = db.collection('users')
  const users = await collection.find({}).toArray()

  return (
    <div>
      <h1>Users List</h1>
      <ul>
        {users.map((user) => (
          <li key={user._id.toString()}>{user.name}</li>
        ))}
      </ul>
    </div>
  )
}

In serverless environments like Vercel, managing database connections efficiently is key to avoiding connection storming. By reusing global variables and understanding the serverless execution model, you can ensure your Next.js app remains stable and performant.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co