🚀 Building Full-Stack Next.js Projects in few simple steps.

WasiWasi
4 min read

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.

0
Subscribe to my newsletter

Read articles from Wasi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Wasi
Wasi