Building a School Management System (SMS) helps educational institutions digitize their operations—streamlining how administrators, teachers, students, and parents interact with school data. In this guide, you'll learn how to build a complete School Management System using the MERN stack (MongoDB, Express.js, React, Node.js).
We’ll cover:
- User authentication
- Student and teacher management
- Class scheduling
- Attendance tracking
- A basic React-based dashboard
Table of Contents
- Project Setup
- Authentication System
- Student Management
- Teacher Management
- Class Scheduling
- Attendance Tracking
- React Frontend Setup
- Conclusion
- Author & Resources
1. Project Setup
Backend Setup
mkdir backend && cd backend
npm init -y
npm install express mongoose dotenv bcryptjs jsonwebtoken cors
Frontend Setup
npx create-react-app frontend
cd frontend
npm install axios react-router-dom
2. Authentication System (Node.js)
/models/User.js
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const userSchema = new mongoose.Schema({
name: String,
email: { type: String, unique: true },
password: String,
role: { type: String, enum: ['admin', 'teacher', 'student'], default: 'student' },
});
userSchema.pre('save', async function () {
if (!this.isModified('password')) return;
this.password = await bcrypt.hash(this.password, 12);
});
module.exports = mongoose.model('User', userSchema);
/routes/userRoutes.js
const express = require('express');
const router = express.Router();
const User = require('../models/User');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
router.post('/register', async (req, res) => {
const { name, email, password, role } = req.body;
const user = new User({ name, email, password, role });
await user.save();
res.status(201).json({ message: 'User registered' });
});
router.post('/login', async (req, res) => {
const { email, password } = req.body;
const user = await User.findOne({ email });
if (!user || !(await bcrypt.compare(password, user.password)))
return res.status(401).json({ error: 'Invalid credentials' });
const token = jwt.sign({ id: user._id, role: user.role }, process.env.JWT_SECRET);
res.json({ token });
});
module.exports = router;
3. Student Management
/models/Student.js
const mongoose = require('mongoose');
const studentSchema = new mongoose.Schema({
name: String,
age: Number,
grade: String,
parentContact: String,
});
module.exports = mongoose.model('Student', studentSchema);
/routes/studentRoutes.js
const express = require('express');
const router = express.Router();
const Student = require('../models/Student');
router.get('/', async (req, res) => {
const students = await Student.find();
res.json(students);
});
router.post('/', async (req, res) => {
const student = new Student(req.body);
await student.save();
res.status(201).json(student);
});
module.exports = router;
4. Teacher Management
/models/Teacher.js
const mongoose = require('mongoose');
const teacherSchema = new mongoose.Schema({
name: String,
subject: String,
email: String,
phone: String,
});
module.exports = mongoose.model('Teacher', teacherSchema);
/routes/teacherRoutes.js
const express = require('express');
const router = express.Router();
const Teacher = require('../models/Teacher');
router.get('/', async (req, res) => {
const teachers = await Teacher.find();
res.json(teachers);
});
router.post('/', async (req, res) => {
const teacher = new Teacher(req.body);
await teacher.save();
res.status(201).json(teacher);
});
module.exports = router;
5. Class Scheduling
/models/Class.js
const mongoose = require('mongoose');
const classSchema = new mongoose.Schema({
className: String,
teacher: { type: mongoose.Schema.Types.ObjectId, ref: 'Teacher' },
students: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Student' }],
scheduleTime: String,
});
module.exports = mongoose.model('Class', classSchema);
/routes/classRoutes.js
const express = require('express');
const router = express.Router();
const Class = require('../models/Class');
router.get('/', async (req, res) => {
const classes = await Class.find().populate('teacher students');
res.json(classes);
});
router.post('/', async (req, res) => {
const newClass = new Class(req.body);
await newClass.save();
res.status(201).json(newClass);
});
module.exports = router;
6. Attendance Tracking
/models/Attendance.js
const mongoose = require('mongoose');
const attendanceSchema = new mongoose.Schema({
student: { type: mongoose.Schema.Types.ObjectId, ref: 'Student' },
date: { type: Date, default: Date.now },
status: { type: String, enum: ['present', 'absent'], default: 'present' },
});
module.exports = mongoose.model('Attendance', attendanceSchema);
/routes/attendanceRoutes.js
const express = require('express');
const router = express.Router();
const Attendance = require('../models/Attendance');
router.post('/', async (req, res) => {
const attendance = new Attendance(req.body);
await attendance.save();
res.status(201).json(attendance);
});
router.get('/:studentId', async (req, res) => {
const records = await Attendance.find({ student: req.params.studentId });
res.json(records);
});
module.exports = router;
7. Frontend Integration (React)
/frontend/src/pages/Dashboard.js
import React, { useEffect, useState } from 'react';
import axios from 'axios';
const Dashboard = () => {
const [students, setStudents] = useState([]);
const [teachers, setTeachers] = useState([]);
useEffect(() => {
axios.get('http://localhost:5000/api/students').then(res => setStudents(res.data));
axios.get('http://localhost:5000/api/teachers').then(res => setTeachers(res.data));
}, []);
return (
<div>
<h1>Dashboard</h1>
<section>
<h2>Students</h2>
<ul>
{students.map(s => (
<li key={s._id}>{s.name} - Grade {s.grade}</li>
))}
</ul>
</section>
<section>
<h2>Teachers</h2>
<ul>
{teachers.map(t => (
<li key={t._id}>{t.name} - {t.subject}</li>
))}
</ul>
</section>
</div>
);
};
export default Dashboard;
8. Conclusion
This School Management System provides:
- Role-based user access
- Student and teacher CRUD operations
- Class scheduling with relationships
- Attendance tracking per student
- A clean React frontend to tie it together
You can deploy this stack using Render (backend) and Netlify/Vercel (frontend), with MongoDB Atlas as your database.
For a production-grade version, consider:
- Role-based access middleware
- Form validation
- PDF generation for reports
- Calendar UI for schedules
9. Author & Resources
Written by: Dhanian
📚 Buy my ebooks & code projects: codewithdhanian.gumroad.com
You’re welcome to build upon this project for your school, freelance gigs, or startup.
Top comments (8)
pretty cool seeing the whole thing broken down this way - you ever run into pain points when scaling one of these up past a small school?
Finding a good schedule of classes with students and teachers (and rooms) can quickly get complex. In Java there is a tool Timefold (former Optiplanner) to compute this kind of problems.
Thanks for sharing
Thanks for your feedback lol
Thank you so much for providing exact code snippets for each part of the system! The step-by-step breakdown from setup to React integration is incredibly helpful for someone diving into the MERN stack.
Would have loved to see a demo of what you've done so far.
Really appreciate how you broke this down, especially the relationships and dashboard. How would you handle scaling permissions or adding granular user roles in a real school?
This is really lit ✨️🤟