MongoDB with Next.js

Integrate MongoDB database with your Next.js application

🍃 What is MongoDB?

MongoDB is a popular NoSQL database that stores data in flexible JSON-like documents. It integrates perfectly with Next.js for building scalable applications with dynamic data requirements and complex queries.


// Install MongoDB driver
npm install mongodb

// Basic MongoDB connection
import { MongoClient } from 'mongodb'

const client = new MongoClient(process.env.MONGODB_URI)
await client.connect()
                                    

Key MongoDB Concepts

📄

Documents

Data stored as JSON-like objects

{
  name: "John",
  age: 30,
  email: "[email protected]"
}
📚

Collections

Groups of related documents

db.collection('users')
  .find()
  .toArray()
🔍

Queries

Find and filter documents easily

db.collection('users')
  .find({ age: { $gt: 25 } })
⚙️

Aggregation

Process and transform data

db.collection('orders')
  .aggregate([
    { $group: { _id: "$status" } }
  ])

🔹 Setting Up MongoDB Connection

Create a reusable MongoDB connection for your Next.js app. This singleton pattern ensures efficient connection pooling and prevents creating multiple database connections across your application.

// lib/mongodb.js
import { MongoClient } from 'mongodb'

const uri = process.env.MONGODB_URI
const options = {}

let client
let clientPromise

if (!process.env.MONGODB_URI) {
  throw new Error('Please add your Mongo URI to .env.local')
}

if (process.env.NODE_ENV === 'development') {
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri, options)
    global._mongoClientPromise = client.connect()
  }
  clientPromise = global._mongoClientPromise
} else {
  client = new MongoClient(uri, options)
  clientPromise = client.connect()
}

export default clientPromise

Environment Variable (.env.local):

MONGODB_URI=mongodb+srv://username:[email protected]/database

🔹 Fetching Data with API Routes

Create API endpoints to interact with MongoDB. Next.js API routes provide a secure backend layer where you can safely query your database without exposing credentials to the client.

// app/api/users/route.js
import { NextResponse } from 'next/server'
import clientPromise from '@/lib/mongodb'

export async function GET() {
  try {
    const client = await clientPromise
    const db = client.db('myDatabase')
    
    const users = await db
      .collection('users')
      .find({})
      .limit(10)
      .toArray()
    
    return NextResponse.json(users)
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to fetch users' },
      { status: 500 }
    )
  }
}

🔹 Displaying Data in Components

Fetch and display MongoDB data in your React components. Use Next.js server components for better performance or client components for interactive features with real-time updates.

// app/users/page.js
'use client'
import { useEffect, useState } from 'react'

export default function UsersPage() {
  const [users, setUsers] = useState([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    async function fetchUsers() {
      const response = await fetch('/api/users')
      const data = await response.json()
      setUsers(data)
      setLoading(false)
    }
    fetchUsers()
  }, [])

  if (loading) return <p>Loading...</p>

  return (
    <div>
      <h1>Users</h1>
      {users.map(user => (
        <div key={user._id}>
          <h3>{user.name}</h3>
          <p>{user.email}</p>
        </div>
      ))}
    </div>
  )
}

🔹 Creating New Documents

Insert new data into MongoDB collections. The insertOne method adds a single document and returns the inserted ID for immediate use in your application.

// app/api/users/route.js
export async function POST(request) {
  try {
    const client = await clientPromise
    const db = client.db('myDatabase')
    const body = await request.json()
    
    const result = await db
      .collection('users')
      .insertOne({
        name: body.name,
        email: body.email,
        createdAt: new Date()
      })
    
    return NextResponse.json({
      message: 'User created',
      userId: result.insertedId
    })
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to create user' },
      { status: 500 }
    )
  }
}

🔹 Updating Documents

Modify existing documents in your MongoDB collection. Use updateOne for single documents or updateMany for bulk updates with flexible query filters.

// app/api/users/[id]/route.js
import { ObjectId } from 'mongodb'

export async function PUT(request, { params }) {
  try {
    const client = await clientPromise
    const db = client.db('myDatabase')
    const body = await request.json()
    
    const result = await db
      .collection('users')
      .updateOne(
        { _id: new ObjectId(params.id) },
        { $set: { name: body.name, email: body.email } }
      )
    
    return NextResponse.json({
      message: 'User updated',
      modifiedCount: result.modifiedCount
    })
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to update user' },
      { status: 500 }
    )
  }
}

🔹 Deleting Documents

Remove documents from your MongoDB collection. Always validate user permissions before allowing delete operations to maintain data security and integrity.

// app/api/users/[id]/route.js
export async function DELETE(request, { params }) {
  try {
    const client = await clientPromise
    const db = client.db('myDatabase')
    
    const result = await db
      .collection('users')
      .deleteOne({ _id: new ObjectId(params.id) })
    
    if (result.deletedCount === 0) {
      return NextResponse.json(
        { error: 'User not found' },
        { status: 404 }
      )
    }
    
    return NextResponse.json({
      message: 'User deleted successfully'
    })
  } catch (error) {
    return NextResponse.json(
      { error: 'Failed to delete user' },
      { status: 500 }
    )
  }
}

🧠 Test Your Knowledge

What type of database is MongoDB?