Back to Blogs
 Connect to MongoDB from the Next.js App Router Project

Connect to MongoDB from the Next.js App Router Project

5 min read
By Avinash

Install the MongoDB Node.js Driver

npm install mongoose

[!NOTE] You should have set up the MongoDB Atlas cluster and have the connection string ready. Add the Shadcn UI dependencies to the project.

npm install @shadcn/ui

Add the below components to the project.

npx shadcn@latest add button
npx shadcn@latest add input
npx shadcn@latest add label
npx shadcn@latest add card
npx shadcn@latest add form
npx shadcn@latest add checkbox
npx shadcn@latest add toast

Add the below dependencies to the project.

npm install lucide-react
npm install sonner

Creating the environment variable in the .env.local file

MONGODB_URI=your_mongodb_connection_string

Creating the connection to the MongoDB database using the mongoose library

Create a new file lib/mongoose.js and add the below code to it.

import mongoose from 'mongoose';

const MONGODB_URI = process.env.MONGODB_URI;

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

let cached = global.mongoose;

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

async function connectDB() {
  if (cached.conn) {
    return cached.conn;
  }

  if (!cached.promise) {
    const opts = {
      bufferCommands: false,
    };

    cached.promise = mongoose.connect(MONGODB_URI, opts).then((mongoose) => {
      return mongoose;
    });
  }

  try {
    cached.conn = await cached.promise;
  } catch (e) {
    cached.promise = null;
    throw e;
  }

  return cached.conn;
}

export default connectDB; 

Create the Todo model

Create a new file models/Todo.js and add the below code to it.

import mongoose from 'mongoose';

const todoSchema = new mongoose.Schema({
  text: {
    type: String,
    required: [true, 'Todo text is required'],
    trim: true,
  },
  completed: {
    type: Boolean,
    default: false,
  },
  createdAt: {
    type: Date,
    default: Date.now,
  },
  updatedAt: {
    type: Date,
    default: Date.now,
  }
}, {
  timestamps: true
});

// Prevent mongoose from creating a plural collection name
const Todo = mongoose.models.Todo || mongoose.model('Todo', todoSchema);

export default Todo; 

Using the connection in the project and create the API routes

Let create a backend API route to test the connection to the MongoDB database.

Create a new file app/api/todos/route.js and add the below code to it.

import { NextResponse } from 'next/server';
import connectDB from '@/lib/mongoose';
import Todo from '@/models/Todo';

export async function GET() {
  try {
    console.log('Connecting to database...');
    await connectDB();
    console.log('Database connected successfully');
    
    console.log('Fetching todos from database...');
    const todos = await Todo.find({}).sort({ createdAt: -1 });
    console.log('Todos fetched successfully:', todos);
    
    return NextResponse.json(todos);
  } catch (error) {
    console.error('Error in GET /api/todos:', error);
    console.error('Error details:', {
      message: error.message,
      stack: error.stack,
      name: error.name
    });
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}

export async function POST(request) {
  try {
    console.log('Connecting to database...');
    await connectDB();
    console.log('Database connected successfully');
    
    const body = await request.json();
    console.log('Received todo data:', body);
    
    console.log('Creating new todo...');
    const todo = await Todo.create({
      text: body.text,
      completed: false,
    });
    console.log('Todo created successfully:', todo);
    
    return NextResponse.json(todo, { status: 201 });
  } catch (error) {
    console.error('Error in POST /api/todos:', error);
    console.error('Error details:', {
      message: error.message,
      stack: error.stack,
      name: error.name
    });
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}

export async function PUT(request) {
  try {
    console.log('Connecting to database...');
    await connectDB();
    console.log('Database connected successfully');
    
    const body = await request.json();
    console.log('Received update data:', body);
    
    console.log('Updating todo...');
    const todo = await Todo.findByIdAndUpdate(
      body._id,
      { 
        text: body.text,
        completed: body.completed,
      },
      { new: true, runValidators: true }
    );
    
    if (!todo) {
      console.error('Todo not found with id:', body._id);
      return NextResponse.json({ error: 'Todo not found' }, { status: 404 });
    }
    
    console.log('Todo updated successfully:', todo);
    return NextResponse.json(todo);
  } catch (error) {
    console.error('Error in PUT /api/todos:', error);
    console.error('Error details:', {
      message: error.message,
      stack: error.stack,
      name: error.name
    });
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
}

export async function DELETE(request) {
  try {
    console.log('Connecting to database...');
    await connectDB();
    console.log('Database connected successfully');
    
    const { searchParams } = new URL(request.url);
    const id = searchParams.get('id');
    console.log('Deleting todo with id:', id);
    
    const todo = await Todo.findByIdAndDelete(id);
    
    if (!todo) {
      console.error('Todo not found with id:', id);
      return NextResponse.json({ error: 'Todo not found' }, { status: 404 });
    }
    
    console.log('Todo deleted successfully:', todo);
    return NextResponse.json({ message: 'Todo deleted successfully' });
  } catch (error) {
    console.error('Error in DELETE /api/todos:', error);
    console.error('Error details:', {
      message: error.message,
      stack: error.stack,
      name: error.name
    });
    return NextResponse.json({ error: error.message }, { status: 500 });
  }
} 

Observe the style of the code.

  • The code is modular and follows the SOLID principles.
  • Usage of try catch blocks to handle errors.
  • Usage of console.log to debug the code.
  • Usage of NextResponse to return the response. We can test the API routes using the curl command or using the Postman tool.

Let's test the API routes using the curl command.

curl -X GET http://localhost:3000/api/todos

This ends the tutorial on how to connect to MongoDB from the Next.js App Router Project and create a backend API route to test the connection to the MongoDB database.