SimpleNext.js

How to use Mongodb in your Next.js project

Cover Image for How to use Mongodb in your Next.js project
Marouane Reda
Marouane Reda
If you need to understand the basics of Next.js, i recommend this course. (Disclaimer : this is an affiliate link that may earn me a small commission, but with no extra cost to you if you choose to enroll)

If you need to integrate a database to your Next.js app, MongoDB is a great choice to consider ( especially if you prefer a NOSQL database for your app). Fortunately, setting up MongoDB with Next.js is pretty straightforward.

Install MongoDB

Pretty straightforward :

npm install mongodb

create a mongoDB Atlas account

MongoDB Atlas is a cloud hosted and self managed database service. In Atlas, you can create an M0 free forever account. (this is only for explanatory purposes, you can set your own mongodb local instance for example if you want to)

in your MongoDB atlas account, you can get your MongoDB URL by hitting the connect button, it will look like this :

mongodb+srv://<USERNAME>:<PASSWORD>@cluster0.tdm0q.mongodb.net/<DBNAME>?retryWrites=true&w=majority

If you are new to MongoDB Atlas, you'll need to go to Database Access section and create a username and password, as well as the Network Access tab to ensure your IP is allowed to connect to the database. However but if you already have a database user and network access enabled, you'll just need to replace the USERNAME and PASSWORD fields with your information.

Create your database and collection

we will call this database sample_db and collection posts for example.

modify env.local file to create MONGODB_URI and MONGODB_DB global variables:

MONGODB_URI=mongodb+srv://<USERNAME>:<PASSWORD>@cluster0.tdm0q.mongodb.net/sample_db?retryWrites=true&w=majority MONGODB_DB=sample_db

Create a connectToDatabase utility

this utility will be used in our pages whenever we want to connect to the database :

under /util/mongodb :

import { MongoClient } from 'mongodb'

const { MONGODB_URI, MONGODB_DB } = process.env

if (!MONGODB_URI) {
  throw new Error(
    'Please define the MONGODB_URI environment variable inside .env.local'
  )
}

if (!MONGODB_DB) {
  throw new Error(
    'Please define the MONGODB_DB environment variable inside .env.local'
  )
}

/**
 * Global is used here to maintain a cached connection across hot reloads
 * in development. This prevents connections growing exponentially
 * during API Route usage.
 */
let cached = global.mongo

if (!cached) {
  cached = global.mongo = { conn: null, promise: null }
}

export async function connectToDatabase() {
  if (cached.conn) {
    return cached.conn
  }

  if (!cached.promise) {
    const opts = {
      useNewUrlParser: true,
      useUnifiedTopology : true
    }

    cached.promise = MongoClient.connect(MONGODB_URI, opts).then((client) => {
      return {
        client,
        db: client.db(MONGODB_DB),
      }
    })
  }
  cached.conn = await cached.promise
  return cached.conn
}

use connectToDatabase to connect to database in our pages, and use the regular MongoDB queries to retrieve our data :

import { connectToDatabase } from "../util/mongodb";

export default function Posts({ posts }) {
return (
<div>
      <h1>My posts</h1>
      <p>
        <small>(only retrieving 10)</small>
      </p>
      <ul>
        {posts.map((post) => (
          <li>
            <h2>{post.title}</h2>
                        <p>{post.content}</p>
          </li>
        ))}
      </ul>
    </div>
);
}

export async function getServerSideProps() {
const { db } = await connectToDatabase();

const posts = await db
.collection(« posts »)
.find({})
.limit(20)
.toArray();

return {
props: {
posts: JSON.parse(JSON.stringify(posts)),
},
};
}

Caveats

do not import any code or component of mongodb in your page if you are not to use it in your getServerSideProps() or getStaticProps(), otherwise you will get this error ( which is not clear enough for me) :

ModuleNotFoundError: Module not found: Error: Can&#39;t resolve &#39;dns&#39; in &#39;node_modules/mongodb/lib&#39;

So, this works fine:

import { findUsers } from '../lib/queries'

function Home({ users }) {
  return (
    <h1>Users list</h1>
    //users.map and so on...
  )
}

export async function getServerSideProps() {
  const users = await findUsers()
  return {
    props: {
      users: users
    }
  }
}

export default Home

While this will throw the error:

import { findUsers } from '../lib/queries'

function Home({ users }) {
  return (
    <h1>Users list</h1>
    //users.map and so on...
  )
}

export async function getServerSideProps() {
  // call disabled to show the error
  // const users = await findUsers()
  return {
    props: {
      users: [] //returned an empty array to avoid other errors
    }
  }
}

export default Home

this will also throw an error ( as you import objectId without using it)

import {ObjectId} from 'mongodb’
import { findUsers } from '../lib/queries'

function Home({ users }) {
  return (
    <h1>Users list</h1>
    //users.map and so on...
  )
}

export async function getServerSideProps() {
  const users = await findUsers()
  return {
    props: {
      users: users
    }
  }
}