DEV Community

Al-Amin Sarker
Al-Amin Sarker

Posted on

Clean MVC Architecture in Node.js Without Express - A Laravel Inspired Approach

A lightweight, framework-free Node.js project demonstrating a clean MVC structure inspired by Laravel. Includes routing, controllers, middleware, MySQL integration, form handling, security and a simple view Engine. All built from scratch.

When most developers think of Node.js, they immediately think of Express.js. But what if you could build a clean MVC architecture routing, controllers, models, views, middleware, security without any framework ? That’s exactly what I built in my project. It’s a lightweight MVC boilerplate that teaches you how frameworks work under the hood.

Why This Project ?

  1. No Frameworks: Everything is plain Node.js. Learn how MVC logic works internally.
  2. MVC Structure: Inspired by Laravel’s clarity and organization.
  3. Secure by Default: Includes CSRF, XSS protection, sessions, CORS and Rate limiting.
  4. Full Feature Set: Routing, controllers, models, validation, API support, view Engine and file uploads.

If you’ve ever wanted to understand what happens behind Express, Laravel or Django, this project is the perfect deep dive.

Routing & Route Service Provider
This project has a custom routing system for web and API endpoints, complete with global middleware and /api prefixes. Routes are defined like Laravel:

// routes/web.js
const Route = require('../system/WebRoute');
const UserController = require('../app/controllers/web/UserController');

Route.get('/users', UserController.index);
Route.post('/users', UserController.store);

module.exports = Route;
Enter fullscreen mode Exit fullscreen mode
// routes/api.js
const Route = require('../system/ApiRoute');

const UserController = require('../app/controllers/api/UserController');
const AuthController = require('../app/controllers/api/AuthController');

Route.post('/users', UserController.store);
Route.post('/login', AuthController.create);

module.exports = Route;
Enter fullscreen mode Exit fullscreen mode

Features:

  • Supports GET, POST, PUT, DELETE.
  • Middleware can be attached per route.

Middleware
Middleware enhances modularity, running before controllers for tasks like logging, authentication, validation, and CSRF protection. Just like Laravel’s pipeline.

const AuthMiddleware = require('../app/middleware/AuthMiddleware');

// Example usage
Route.post('/users', UserController.store, [AuthMiddleware]);
Enter fullscreen mode Exit fullscreen mode

Controllers
Controllers manage the business logic and prepare responses for web or API routes:

// app/controllers/api/UserController.js
const response = require('../../../helpers/response');
const User = require('../../models/User');

class UserController {
  async index(req, res) {
    const users = await User.all();

    return response.json(res, {
        success: true,
        message: 'Success',
        data: users,
     });
  }
}

module.exports = new UserController();
Enter fullscreen mode Exit fullscreen mode

Models with Fillable Support
Models extend a base Model class and define fillable fields to prevent mass assignment vulnerabilities. Just like Laravel’s fillable fields, models prevent mass assignment vulnerabilities.

// app/models/User.js
const Model = require('../../system/Model');

class User extends Model {
   constructor() {
     super('users', ['name', 'email', 'password']);
   }
}

module.exports = new User();
Enter fullscreen mode Exit fullscreen mode

Only name, email and password can be mass-assigned.

Usage in a controller:

await User.create({
   name: 'Alamin',
   email: 'alamin@gmail.com',
   password: hash('1234')
});
Enter fullscreen mode Exit fullscreen mode

View Engine
A minimalist templating engine allows server-side rendering with simple HTML interpolation, similar to Blade or EJS.
View Template (views/home.html):

<html>
  <head><title>{{ title }}</title></head>
  <body>
     {{ content }}
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Render from Controller:

const html = await view('home', { 
  title: 'Hello Node.js', 
  content: 'Hello World!' 
});
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
Enter fullscreen mode Exit fullscreen mode

Security First
The project includes essential security protections by default:

  1. CSRF Tokens for safe form submissions in web routes.
  2. XSS Sanitization using sanitize-html
  3. CORS Middleware for safe cross-origin requests.
  4. Rate Limiting to prevent abuse.
  5. Request Loggin for debugging and monitoring.

Form Handling & File Uploads
Supports application/json, x-www-form-urlencoded and multipart/form-data (via formidable)

const Validation = require('../../../system/Validation');

const { passes, errors } = await Validation.validate(
    { name, email, password },
    {
      name: 'required|min:3',
      email: 'required|email|unique:users,email',
      password: 'required|min:3'
    }
);

if (! passes) {
  return response.validationError(res, errors);
}
Enter fullscreen mode Exit fullscreen mode

Quick Start

git clone git@github.com:alamincse/mvc-app-nodejs.git
cd mvc-app-nodejs
npm install
Enter fullscreen mode Exit fullscreen mode

Run the server:

nodemon server
node server # or
npm run pm2:start # or use pm2
Enter fullscreen mode Exit fullscreen mode

And create database tables with:

nodemon database  # Or `node database`
Enter fullscreen mode Exit fullscreen mode

Configure your .env file for database credentials and ports.

Access the Application
Open your browser and navigate to http://localhost:3000

Why This Architecture Stands Out ?

  1. Pure JavaScript: No reliance on Express or other heavy frameworks.
  2. Understand MVC deeply: Learn core patterns and workflows.
  3. Security-first: Shields common attacks with default middleware.
  4. Feature-rich: Includes templating, validation, models, routing, APIs.
  5. Ideal for learning: Perfect for developers keen on diving into MVC fundamentals.

Why You Should Try It ?

  1. Understand frameworks deeply: You’ll never see Express or Laravel the same way again.
  2. Educational: Great for students and self-learners.
  3. Extensible: Your own middleware, validation or auth system.
  4. Lightweight: Perfect for small projects and experiments.

Final Thoughts
Building mvc-app-nodejs demonstrates that frameworks are essentially layers of abstraction. By building an MVC system from scratch, you gain insight into the inner workings of routing, controllers, models, views and middleware.

Read more on the GitHub repository: MVC-APP-Nodejs

Top comments (0)