DEV Community

CodeWithDhanian
CodeWithDhanian

Posted on

43 4 2 5 3

How to Build a School Management System: A Complete Guide with Code Snippets

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

  1. Project Setup
  2. Authentication System
  3. Student Management
  4. Teacher Management
  5. Class Scheduling
  6. Attendance Tracking
  7. React Frontend Setup
  8. Conclusion
  9. Author & Resources

1. Project Setup

Backend Setup

mkdir backend && cd backend
npm init -y
npm install express mongoose dotenv bcryptjs jsonwebtoken cors
Enter fullscreen mode Exit fullscreen mode

Frontend Setup

npx create-react-app frontend
cd frontend
npm install axios react-router-dom
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

/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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

/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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

/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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

/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;
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

/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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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.

Tiugo image

Modular, Fast, and Built for Developers

CKEditor 5 gives you full control over your editing experience. A modular architecture means you get high performance, fewer re-renders and a setup that scales with your needs.

Start now

Top comments (8)

Collapse
 
nevodavid profile image
Nevo David

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?

Collapse
 
maglagla profile image
Markus Glagla

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.

Collapse
 
code_2 profile image
CodeWithDhanian

Thanks for sharing

Collapse
 
code_2 profile image
CodeWithDhanian

Thanks for your feedback lol

Collapse
 
cwrite profile image
Christopher Wright

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.

Collapse
 
arize99 profile image
Arize Nnonyelu

Would have loved to see a demo of what you've done so far.

Collapse
 
dotallio profile image
Dotallio

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?

Collapse
 
edehchi59 profile image
Edeh chinedu

This is really lit ✨️🤟

👋 Kindness is contagious

Dive into this thoughtful piece, beloved in the supportive DEV Community. Coders of every background are invited to share and elevate our collective know-how.

A sincere "thank you" can brighten someone's day—leave your appreciation below!

On DEV, sharing knowledge smooths our journey and tightens our community bonds. Enjoyed this? A quick thank you to the author is hugely appreciated.

Okay