🚀 Building Full-Stack Next.js Projects in few simple steps.
As a pre-final year Computer Science student, I’ve always been fascinated by the power of full-stack web development. Recently, I decided to build a project using the latest version of Next.js and MongoDB with Mongoose. In this blog, I’ll walk you through the steps I took to create a simple full-stack app using these technologies.
🛠️ Setting Up the Project
Before we start, make sure you have Node.js installed. We’ll also be using MongoDB as our database. If you don’t have MongoDB installed locally, you can quickly set up a free database with MongoDB Atlas.
Step 1: Create a New Next.js Project
Start by creating a new Next.js project using the latest version with the app
directory:
npx create-next-app@latest my-fullstack-app --experimental-app
cd my-fullstack-app
This command sets up a Next.js project with the new app
directory structure, making it easier to manage routes, layouts, and API endpoints.
🌐 Step 2: Connect to MongoDB with Mongoose
Next.js, combined with MongoDB and Mongoose, provides a powerful full-stack development experience. Here’s how to set up the connection.
Step 2.1: Install Mongoose
First, let’s install Mongoose, a popular ODM (Object Data Modeling) library for MongoDB.
npm install mongoose
Step 2.2: Create a Database Connection File
Create a lib/mongoose.js
file to handle the MongoDB connection using Mongoose:
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 dbConnect() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
cached.promise = mongoose.connect(MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
}).then((mongoose) => {
return mongoose;
});
}
cached.conn = await cached.promise;
return cached.conn;
}
export default dbConnect;
Step 2.3: Set Up Environment Variables
Create a .env.local
file in the root of your project to store your MongoDB connection string:
MONGODB_URI=mongodb+srv://<username>:<password>@cluster0.mongodb.net/mydatabase?retryWrites=true&w=majority
Replace <username>
, <password>
, and mydatabase
with your MongoDB Atlas credentials.
🚧 Step 3: Create Mongoose Models and API Routes
Step 3.1: Define a Mongoose Model
Inside the app/api/
directory, create a new folder models/
and add a file User.js
to define your Mongoose schema:
import mongoose from 'mongoose';
const UserSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
unique: true,
},
});
export default mongoose.models.User || mongoose.model('User', UserSchema);
Step 3.2: Create an API Route
Next, create an API route to interact with your MongoDB database. Inside the app/api/
directory, create a new folder users/
and add a file route.js
:
import dbConnect from '../../../lib/mongoose';
import User from '../../../models/User';
export async function GET() {
await dbConnect();
const users = await User.find({});
return new Response(JSON.stringify(users), {
headers: { 'Content-Type': 'application/json' },
});
}
export async function POST(req) {
await dbConnect();
const body = await req.json();
const newUser = new User(body);
await newUser.save();
return new Response(JSON.stringify(newUser), {
headers: { 'Content-Type': 'application/json' },
});
}
This code creates a GET endpoint to fetch all users and a POST endpoint to add a new user.
🧩 Step 4: Creating a Simple UI
Now, let’s create a simple UI to interact with our API. Open app/page.js
and update it with a form to add users and a list to display them:
'use client';
import { useState, useEffect } from 'react';
export default function Home() {
const [users, setUsers] = useState([]);
const [name, setName] = useState('');
const [email, setEmail] = useState('');
useEffect(() => {
fetch('/api/users')
.then((res) => res.json())
.then((data) => setUsers(data));
}, []);
const addUser = async (e) => {
e.preventDefault();
const res = await fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, email }),
});
const newUser = await res.json();
setUsers([...users, newUser]);
setName('');
setEmail('');
};
return (
<div>
<h1>User List</h1>
<ul>
{users.map((user) => (
<li key={user._id}>{user.name} - {user.email}</li>
))}
</ul>
<form onSubmit={addUser}>
<input
type="text"
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
/>
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button type="submit">Add User</button>
</form>
</div>
);
}
🎉 Step 5: Run Your Project
Finally, let’s run the project and see it in action:
npm run dev
Visit http://localhost:3000
in your browser. You should see a simple form to add users and a list of users fetched from your MongoDB database.
And that’s it! 🎉 You’ve built a full-stack Next.js application with MongoDB and Mongoose. As a pre-final year Computer Science student, this project gave me a hands-on understanding of how to connect frontend and backend technologies seamlessly.
Feel free to extend this project by adding more features, such as authentication, user profiles, and more. Happy coding!
Thanks for reading! If you found this guide helpful, be sure to follow me for more content on web development, full-stack projects, and more.
Subscribe to my newsletter
Read articles from Wasi directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by