Creating a Scalable MVC Folder Structure in Node.js
When building a Node.js application, it’s crucial to have a well-organized folder structure to keep your codebase maintainable and scalable. The Model-View-Controller (MVC) pattern is a popular design pattern that helps achieve this by separating concerns into different components: models, views, and controllers. In this blog, we will explore how to set up an MVC folder structure within a src
directory for a Node.js project.
Why Use MVC?
The MVC pattern helps in:
- Separation of Concerns: Each part of the application is responsible for a specific functionality, making the codebase cleaner and easier to manage.
- Scalability: As your application grows, the MVC pattern helps maintain structure and organization.
- Reusability: Components can be reused across different parts of the application.
Setting Up the Folder Structure
Let’s start by creating the basic folder structure:
project-root/
│
├── src/ # Source files
│ ├── config/ # Configuration files (database, environment variables, etc.)
│ │ └── config.js
│ │
│ ├── controllers/ # Controllers to handle the application logic
│ │ ├── userController.js
│ │ ├── productController.js
│ │ └── ...
│ │
│ ├── models/ # Models to represent the data structures
│ │ ├── user.js
│ │ ├── product.js
│ │ └── ...
│ │
│ ├── routes/ # Routes to define the endpoints and associate them with controllers
│ │ ├── userRoutes.js
│ │ ├── productRoutes.js
│ │ └── ...
│ │
│ ├── views/ # Views for rendering the HTML templates (if using a template engine)
│ │ ├── layouts/
│ │ │ └── main.hbs
│ │ ├── user/
│ │ │ ├── profile.hbs
│ │ │ └── ...
│ │ └── ...
│ │
│ ├── middleware/ # Custom middleware functions
│ │ └── authMiddleware.js
│ │
│ ├── public/ # Public assets (images, CSS, JavaScript files)
│ │ ├── css/
│ │ ├── js/
│ │ └── images/
│ │
│ ├── utils/ # Utility functions and helpers
│ │ └── helper.js
│ │
│ └── app.js # Main application file
│
├── .env # Environment variables
├── .gitignore # Git ignore file
├── package.json # NPM package file
└── README.md # Project documentation
Folder Breakdown
src/config/
This folder contains configuration files, such as database settings and environment variables.
Example (config.js
):
module.exports = {
db: {
uri: process.env.DB_URI,
},
port: process.env.PORT || 3000,
};
src/controllers/
Controllers handle the application logic and interact with models to process requests.
Example (userController.js
):
const User = require('../models/user');
exports.getUser = async (req, res) => {
try {
const user = await User.findById(req.params.id);
res.status(200).json(user);
} catch (error) {
res.status(500).json({ error: error.message });
}
};
src/models/
Models define the data structures and interact with the database.
Example (user.js
):
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: String,
email: String,
password: String,
});
module.exports = mongoose.model('User', userSchema);
src/routes/
Routes define the endpoints of the application and map them to corresponding controllers.
Example (userRoutes.js
):
const express = require('express');
const router = express.Router();
const userController = require('../controllers/userController');
router.get('/:id', userController.getUser);
module.exports = router;
src/views/
Views contain templates for rendering HTML (if using a templating engine).
Example (layouts/main.hbs
):
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
</head>
<body>
{{{body}}}
</body>
</html>
src/middleware/
Custom middleware functions used across the application.
Example (authMiddleware.js
):
module.exports = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect(‘/login’);
};
module.exports = (req, res, next) => {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login');
};
src/public/
Contains publicly accessible assets like CSS, JavaScript files, and images.
src/utils/
Utility functions and helper methods.
Example (helper.js
):
exports.formatDate = (date) => {
return new Date(date).toLocaleDateString();
};
src/app.js
The main application file where the Express app is set up and configured.
Example (app.js
):
const express = require('express');
const app = express();
const userRoutes = require('./routes/userRoutes');
app.use(express.json());
app.use('/users', userRoutes);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Conclusion
Using the MVC pattern in a Node.js application helps in maintaining a clean, scalable, and organized codebase. This folder structure ensures that different concerns are separated, making the development process more efficient. By following this structure, you can create robust and maintainable applications.