Student Registration App: MERN

MERN Student Registration CRUD App

Features

Add Student
View Students
Edit Student
Update Student
Delete Student
Search Student
Email Validation
Phone Number Validation

In this project, we will build a Student Registration System using the MERN Stack, which includes MongoDB, Express.js, React, and Node.js. We will create a full-stack application that performs CRUD operations (Create, Read, Update, Delete) and handles data between frontend and backend.

Prerequisites:

Before starting, make sure you have:

  • Basic knowledge of HTML, CSS, and JavaScript

      Course link: Web Development : From Fundamentals to Advanced

  • Understanding of React basics (components, state)
  • Node.js and npm installed
  • MongoDB installed and running (or MongoDB Atlas)
  • A code editor like VS Code

This project will help you understand how a real-world full-stack application works from UI to database.

Step by Step Procedure: 

Step 1: Create Project Folder

mkdir 2_Student_Registration_App
cd 2_Student_Registration_App

Step 2: Create Backend and Frontend Folders

mkdir backend frontend

Backend Setup

Step 3: Go Inside Backend Folder

cd backend

Step 4: Initialize Node.js Project

npm init -y

Step 5: Install Backend Packages

npm install express mongoose cors dotenv

Step 6: Install Nodemon

npm install nodemon --save-dev

Step 7: Create Backend Folder Structure

mkdir models

Create files:

backend
├── models
│ └── Student.js
├── server.js
├── .env
└── package.json

⚠️ Important: File name should be Student.js, not Student.json.


Step 8: Create .env

Create backend/.env

PORT=5000
MONGO_URI=mongodb://127.0.0.1:27017/student_registration_db

Step 9: Update package.json

In backend/package.json, update only the scripts section:

"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
}

Step 10: Create Student Model

Create backend/models/Student.js

const mongoose = require("mongoose");

const studentSchema = new mongoose.Schema(
{
name: {
type: String,
required: [true, "Student name is required"],
trim: true,
minlength: [3, "Name must be at least 3 characters"],
},

email: {
type: String,
required: [true, "Email is required"],
trim: true,
lowercase: true,
match: [
/^[^\s@]+@[^\s@]+\.[^\s@]+$/,
"Please enter a valid email address",
],
},

phone: {
type: String,
required: [true, "Phone number is required"],
trim: true,
match: [/^[0-9]{10}$/, "Phone number must be exactly 10 digits"],
},

course: {
type: String,
required: [true, "Course name is required"],
trim: true,
minlength: [2, "Course name must be at least 2 characters"],
},

city: {
type: String,
required: [true, "City is required"],
trim: true,
minlength: [2, "City name must be at least 2 characters"],
},
},
{
timestamps: true,
}
);

const Student = mongoose.model("Student", studentSchema);

module.exports = Student;

Step 11: Create Backend Server

Create backend/server.js

require("dotenv").config();

const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const Student = require("./models/Student");

const app = express();

// Middleware
app.use(cors());
app.use(express.json());

// Environment Variables
const PORT = process.env.PORT || 5000;
const MONGO_URI = process.env.MONGO_URI;

// MongoDB Connection
if (!MONGO_URI) {
console.log("MongoDB Error: MONGO_URI is missing in .env file");
} else {
mongoose
.connect(MONGO_URI)
.then(() => console.log("MongoDB Connected Successfully"))
.catch((error) => console.log("MongoDB Error:", error.message));
}

// Test Route
app.get("/", (req, res) => {
res.send("Student Registration Backend Running");
});

// CREATE Student
app.post("/api/students", async (req, res) => {
try {
const { name, email, phone, course, city } = req.body;

const newStudent = new Student({
name,
email,
phone,
course,
city,
});

await newStudent.save();

res.status(201).json({
message: "Student added successfully",
student: newStudent,
});
} catch (error) {
res.status(400).json({
message: "Error adding student",
error: error.message,
});
}
});

// READ All Students
app.get("/api/students", async (req, res) => {
try {
const students = await Student.find().sort({ createdAt: -1 });
res.status(200).json(students);
} catch (error) {
res.status(500).json({
message: "Error fetching students",
error: error.message,
});
}
});

// UPDATE Student
app.put("/api/students/:id", async (req, res) => {
try {
const { name, email, phone, course, city } = req.body;

const updatedStudent = await Student.findByIdAndUpdate(
req.params.id,
{
name,
email,
phone,
course,
city,
},
{
new: true,
runValidators: true,
}
);

if (!updatedStudent) {
return res.status(404).json({
message: "Student not found",
});
}

res.status(200).json({
message: "Student updated successfully",
student: updatedStudent,
});
} catch (error) {
res.status(400).json({
message: "Error updating student",
error: error.message,
});
}
});

// DELETE Student
app.delete("/api/students/:id", async (req, res) => {
try {
const deletedStudent = await Student.findByIdAndDelete(req.params.id);

if (!deletedStudent) {
return res.status(404).json({
message: "Student not found",
});
}

res.status(200).json({
message: "Student deleted successfully",
});
} catch (error) {
res.status(500).json({
message: "Error deleting student",
error: error.message,
});
}
});

// Start Server
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

Step 12: Run Backend

npm run dev

Expected output:

MongoDB Connected Successfully
Server running on port 5000

Backend URL:

http://localhost:5000

Frontend Setup

Step 13: Open New Terminal and Go to Frontend Folder

cd 2_Student_Registration_App/frontend

Or from backend folder:

cd ../frontend

Step 14: Create React App Using Vite

npm create vite@latest .

Choose:

React
JavaScript

Step 15: Install Frontend Dependencies

npm install

Step 16: Install Axios

npm install axios

Step 17: Update App.jsx

Replace frontend/src/App.jsx

import { useEffect, useState } from "react";
import axios from "axios";
import "./App.css";

const API_URL = "http://localhost:5000/api/students";

function App() {
const [formData, setFormData] = useState({
name: "",
email: "",
phone: "",
course: "",
city: "",
});

const [students, setStudents] = useState([]);
const [editingId, setEditingId] = useState(null);
const [search, setSearch] = useState("");

const fetchStudents = async () => {
try {
const response = await axios.get(API_URL);
setStudents(response.data);
} catch (error) {
console.log("Error fetching students:", error);
}
};

useEffect(() => {
fetchStudents();
}, []);

const handleChange = (e) => {
const { name, value } = e.target;

if (name === "phone") {
const onlyNumbers = value.replace(/[^0-9]/g, "");

setFormData({
...formData,
[name]: onlyNumbers,
});
} else {
setFormData({
...formData,
[name]: value,
});
}
};

const clearForm = () => {
setFormData({
name: "",
email: "",
phone: "",
course: "",
city: "",
});

setEditingId(null);
};

const handleSubmit = async (e) => {
e.preventDefault();

if (formData.phone.length !== 10) {
alert("Phone number must be exactly 10 digits");
return;
}

try {
if (editingId) {
await axios.put(`${API_URL}/${editingId}`, formData);
alert("Student updated successfully");
} else {
await axios.post(API_URL, formData);
alert("Student added successfully");
}

clearForm();
fetchStudents();
} catch (error) {
console.log("Error saving student:", error);

if (error.response && error.response.data && error.response.data.error) {
alert(error.response.data.error);
} else {
alert("Something went wrong");
}
}
};

const handleEdit = (student) => {
setEditingId(student._id);

setFormData({
name: student.name,
email: student.email,
phone: student.phone,
course: student.course,
city: student.city,
});
};

const handleDelete = async (id) => {
const confirmDelete = window.confirm(
"Are you sure you want to delete this student?"
);

if (!confirmDelete) {
return;
}

try {
await axios.delete(`${API_URL}/${id}`);
alert("Student deleted successfully");
fetchStudents();
} catch (error) {
console.log("Error deleting student:", error);
alert("Something went wrong");
}
};

const filteredStudents = students.filter((student) => {
return (
student.name.toLowerCase().includes(search.toLowerCase()) ||
student.email.toLowerCase().includes(search.toLowerCase()) ||
student.phone.toLowerCase().includes(search.toLowerCase()) ||
student.course.toLowerCase().includes(search.toLowerCase()) ||
student.city.toLowerCase().includes(search.toLowerCase())
);
});

return (
<div className="app">
<header className="header">
<h1>VMS CLASS</h1>
<p>Student Registration Management System</p>
</header>

<main className="dashboard">
<section className="card form-card">
<h2>{editingId ? "Update Student" : "Register Student"}</h2>

<form onSubmit={handleSubmit}>
<input
type="text"
name="name"
placeholder="Enter Student Name"
value={formData.name}
onChange={handleChange}
minLength="3"
required
/>

<input
type="email"
name="email"
placeholder="Enter Email Address"
value={formData.email}
onChange={handleChange}
required
/>

<input
type="tel"
name="phone"
placeholder="Enter 10 Digit Phone Number"
value={formData.phone}
onChange={handleChange}
pattern="[0-9]{10}"
maxLength="10"
title="Phone number must be exactly 10 digits"
required
/>

<input
type="text"
name="course"
placeholder="Enter Course Name"
value={formData.course}
onChange={handleChange}
minLength="2"
required
/>

<input
type="text"
name="city"
placeholder="Enter City"
value={formData.city}
onChange={handleChange}
minLength="2"
required
/>

<button type="submit" className="submit-btn">
{editingId ? "Update Student" : "Add Student"}
</button>

{editingId && (
<button type="button" className="cancel-btn" onClick={clearForm}>
Cancel
</button>
)}
</form>
</section>

<section className="card table-card">
<div className="table-header">
<div>
<h2>Registered Students</h2>
<p>Total Students: {students.length}</p>
</div>

<input
type="text"
placeholder="Search student..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="search-box"
/>
</div>

<div className="table-wrapper">
<table>
<thead>
<tr>
<th>Sl No</th>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Course</th>
<th>City</th>
<th>Actions</th>
</tr>
</thead>

<tbody>
{filteredStudents.length > 0 ? (
filteredStudents.map((student, index) => (
<tr key={student._id}>
<td>{index + 1}</td>
<td>{student.name}</td>
<td>{student.email}</td>
<td>{student.phone}</td>
<td>{student.course}</td>
<td>{student.city}</td>
<td>
<button
className="edit-btn"
onClick={() => handleEdit(student)}
>
Edit
</button>

<button
className="delete-btn"
onClick={() => handleDelete(student._id)}
>
Delete
</button>
</td>
</tr>
))
) : (
<tr>
<td colSpan="7" className="no-data">
No students found
</td>
</tr>
)}
</tbody>
</table>
</div>
</section>
</main>
</div>
);
}

export default App;

Step 18: Update App.css

Replace frontend/src/App.css

* {
box-sizing: border-box;
}

body {
margin: 0;
font-family: Arial, sans-serif;
background: #eef2f7;
color: #222;
}

.app {
min-height: 100vh;
}

.header {
background: linear-gradient(135deg, #101820, #1f4068);
color: white;
text-align: center;
padding: 35px 20px;
}

.header h1 {
margin: 0;
font-size: 42px;
color: #00ff99;
letter-spacing: 2px;
}

.header p {
margin-top: 8px;
font-size: 20px;
color: #ffd700;
}

.dashboard {
width: 95%;
max-width: 1300px;
margin: 30px auto;
display: grid;
grid-template-columns: 350px 1fr;
gap: 25px;
}

.card {
background: white;
border-radius: 16px;
padding: 25px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.08);
}

.form-card h2,
.table-card h2 {
margin-top: 0;
color: #1f4068;
}

form {
display: flex;
flex-direction: column;
gap: 14px;
}

input {
padding: 13px;
border: 1px solid #ccd3dd;
border-radius: 10px;
font-size: 15px;
outline: none;
}

input:focus {
border-color: #00b894;
}

.submit-btn,
.cancel-btn,
.edit-btn,
.delete-btn {
border: none;
padding: 11px 14px;
border-radius: 9px;
cursor: pointer;
font-weight: bold;
}

.submit-btn {
background: #00b894;
color: white;
}

.submit-btn:hover {
background: #019875;
}

.cancel-btn {
background: #636e72;
color: white;
}

.table-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 12px;
margin-bottom: 20px;
}

.table-header p {
margin: 5px 0 0;
color: #666;
}

.search-box {
width: 250px;
}

.table-wrapper {
overflow-x: auto;
}

table {
width: 100%;
border-collapse: collapse;
min-width: 850px;
}

th {
background: #1f4068;
color: white;
padding: 13px;
text-align: left;
}

td {
padding: 13px;
border-bottom: 1px solid #e5e7eb;
}

tr:hover {
background: #f8fafc;
}

.edit-btn {
background: #0984e3;
color: white;
margin-right: 8px;
}

.delete-btn {
background: #d63031;
color: white;
}

.no-data {
text-align: center;
padding: 25px;
color: #777;
}

@media (max-width: 900px) {
.dashboard {
grid-template-columns: 1fr;
}

.search-box {
width: 100%;
}

.table-header {
flex-direction: column;
align-items: stretch;
}
}

Step 19: Run Backend

Open terminal inside backend:

cd backend
npm run dev

Step 20: Run Frontend

Open another terminal inside frontend:

cd frontend
npm run dev

Open:

http://localhost:5173

Validation Added

Frontend HTML Validation

Name minimum 3 characters
Email must be valid email format
Phone must be exactly 10 digits
Course minimum 2 characters
City minimum 2 characters

Backend Mongoose Validation

Email format validation
Phone number must be exactly 10 digits
Required fields validation
Minimum length validation

API Routes

POST   /api/students       Add Student
GET /api/students View Students
PUT /api/students/:id Update Student
DELETE /api/students/:id Delete Student

Final Project Flow

React Form

HTML Validation

Axios API Request

Express Backend

Mongoose Validation

MongoDB Database

Response Back to React

Student Table Updated

Summary

This project is a complete MERN Stack CRUD application for managing student registrations.
Users can add, view, update, delete, and search student data through a React frontend connected to a Node.js + Express backend.
MongoDB stores the data using Mongoose, with validations applied on both frontend and backend.
It demonstrates the full data flow from UI → API → database → and back to UI.

Keywords

mern stack project
mern stack crud project
student registration project
student management system
react node project
react crud app
node js crud project
mongodb project
express js project
full stack project
web development project
react project for beginners
node js project for beginners
mern stack tutorial
crud application example

Previous Topic The Rising of AI