Kritim Yantra
Aug 13, 2025
If you've ever started building a simple to-do list and thought, “I want to save tasks for real users — but I have no idea how to set up a database with Next.js”, trust me: you’re not alone.
A lot of beginner devs (me included back in the day) struggle with this part.
The good news? You don’t need to know backend engineering to build a real full-stack app with Next.js and MongoDB.
In this step-by-step guide, we’re going to build a complete To-Do app that:
Let’s do this — in plain, simple terms. 💪
Open your terminal and run:
npx create-next-app@latest nextjs-todo-mongodb
Once it’s done:
cd nextjs-todo-mongodb
npm run dev
Now head to http://localhost:3000
— your project is live!
Create a free account and a new project.
todoDB
tasks
mongodb+srv://<username>:<password>@cluster0.mongodb.net/?retryWrites=true&w=majority
👉 Replace <username>
and <password>
with your MongoDB credentials.
In your project root, create a file:
touch .env.local
Add this:
MONGODB_URI=mongodb+srv://your_username:your_password@cluster0.mongodb.net/todoDB?retryWrites=true&w=majority
✅ Pro Tip: Never hard-code credentials in your code. Always use environment variables.
Install the official MongoDB driver:
npm install mongodb
Then, create a folder:
mkdir lib
touch lib/mongodb.js
Inside 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') {
// Reuse connection in dev mode
if (!global._mongoClientPromise) {
client = new MongoClient(uri, options);
global._mongoClientPromise = client.connect();
}
clientPromise = global._mongoClientPromise;
} else {
// New connection in production
client = new MongoClient(uri, options);
clientPromise = client.connect();
}
export default clientPromise;
Let’s make an API that can talk to MongoDB.
Create a file:
mkdir pages/api/tasks
touch pages/api/tasks/index.js
pages/api/tasks/index.js
(GET + POST)import clientPromise from '../../../lib/mongodb';
export default async function handler(req, res) {
const client = await clientPromise;
const db = client.db('todoDB');
const collection = db.collection('tasks');
if (req.method === 'GET') {
const tasks = await collection.find({}).toArray();
res.json(tasks);
}
if (req.method === 'POST') {
const { title } = req.body;
const result = await collection.insertOne({ title });
res.json(result);
}
}
pages/api/tasks/[id].js
:
import clientPromise from '../../../lib/mongodb';
import { ObjectId } from 'mongodb';
export default async function handler(req, res) {
const client = await clientPromise;
const db = client.db('todoDB');
const collection = db.collection('tasks');
const id = req.query.id;
if (req.method === 'DELETE') {
const result = await collection.deleteOne({ _id: new ObjectId(id) });
res.json(result);
}
}
Replace everything in pages/index.js
with:
import { useEffect, useState } from 'react';
export default function Home() {
const [tasks, setTasks] = useState([]);
const [title, setTitle] = useState('');
useEffect(() => {
fetchTasks();
}, []);
const fetchTasks = async () => {
const res = await fetch('/api/tasks');
const data = await res.json();
setTasks(data);
};
const addTask = async () => {
await fetch('/api/tasks', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title }),
});
setTitle('');
fetchTasks();
};
const deleteTask = async (id) => {
await fetch(`/api/tasks/${id}`, {
method: 'DELETE',
});
fetchTasks();
};
return (
<div style={{ padding: 40 }}>
<h1>📝 To-Do App</h1>
<input
value={title}
onChange={(e) => setTitle(e.target.value)}
placeholder="New Task"
/>
<button onClick={addTask}>Add</button>
<ul>
{tasks.map((task) => (
<li key={task._id}>
{task.title}{' '}
<button onClick={() => deleteTask(task._id)}>❌</button>
</li>
))}
</ul>
</div>
);
}
MONGODB_URI
in Vercel environment variablesDone 🎉 — your full-stack app is live!
Nope! Next.js API routes act as your backend.
Yes! The shared tier on MongoDB Atlas is great for learning and small apps.
Yes, but Vercel makes it easier. You can also deploy via Netlify or even Docker if you prefer.
Have you built something cool with Next.js and MongoDB?
Ran into any roadblocks along the way?
👇 Drop your questions, bugs, or even your finished projects in the comments!
No comments yet. Be the first to comment!
Please log in to post a comment:
Sign in with Google