Best Practices for Structuring Node.js Projects
Learn how to organize your Node.js application files and directories for better maintainability and scalability.
0 likes
182 views
Rule Content
{
"title": "Best Practices for Structuring Node.js Projects",
"description": "Learn how to organize your Node.js application files and directories for better maintainability and scalability.",
"category": "Node.js Cursor Rules",
"rules": [
{
"name": "Organize Code by Feature",
"description": "Structure your project by grouping related files (models, controllers, routes) within feature-specific directories to enhance modularity and maintainability.",
"recommendation": "Adopt a feature-based directory structure where each feature has its own folder containing all related components.",
"example": {
"before": "āāā controllers/\nāāā models/\nāāā routes/\nāāā services/\nāāā utils/",
"after": "āāā user/\nā āāā userController.js\nā āāā userModel.js\nā āāā userRoutes.js\nā āāā userService.js\nāāā product/\nā āāā productController.js\nā āāā productModel.js\nā āāā productRoutes.js\nā āāā productService.js\nāāā utils/"
}
},
{
"name": "Separate Configuration Files",
"description": "Store configuration settings in dedicated files or environment variables to manage different environments and enhance security.",
"recommendation": "Use a 'config' directory to house environment-specific configuration files and utilize environment variables for sensitive information.",
"example": {
"before": "const dbHost = 'localhost';\nconst dbUser = 'root';\nconst dbPass = 'password';",
"after": "// .env\nDB_HOST=localhost\nDB_USER=root\nDB_PASS=password\n\n// config/database.js\nrequire('dotenv').config();\nmodule.exports = {\n host: process.env.DB_HOST,\n user: process.env.DB_USER,\n pass: process.env.DB_PASS,\n};"
}
},
{
"name": "Implement Middleware Separately",
"description": "Organize middleware functions in a dedicated directory to promote reusability and maintainability.",
"recommendation": "Create a 'middleware' directory to store all middleware functions, each handling a specific responsibility.",
"example": {
"before": "app.use((req, res, next) => {\n // Authentication logic\n next();\n});\napp.use((req, res, next) => {\n // Logging logic\n next();\n});",
"after": "// middleware/auth.js\nmodule.exports = (req, res, next) => {\n // Authentication logic\n next();\n};\n\n// middleware/logger.js\nmodule.exports = (req, res, next) => {\n // Logging logic\n next();\n};\n\n// app.js\nconst auth = require('./middleware/auth');\nconst logger = require('./middleware/logger');\napp.use(auth);\napp.use(logger);"
}
},
{
"name": "Use Asynchronous Code",
"description": "Utilize asynchronous programming patterns to improve performance and scalability.",
"recommendation": "Employ async/await syntax for handling asynchronous operations to avoid callback hell and enhance code readability.",
"example": {
"before": "function getData() {\n fetchData1((err, data1) => {\n if (err) return handleError(err);\n fetchData2(data1, (err, data2) => {\n if (err) return handleError(err);\n fetchData3(data2, (err, data3) => {\n if (err) return handleError(err);\n processData(data3);\n });\n });\n });\n}",
"after": "async function getData() {\n try {\n const data1 = await fetchData1();\n const data2 = await fetchData2(data1);\n const data3 = await fetchData3(data2);\n processData(data3);\n } catch (err) {\n handleError(err);\n }\n}"
}
},
{
"name": "Maintain Consistent Naming Conventions",
"description": "Use consistent and meaningful naming conventions for files and directories to improve code readability and maintainability.",
"recommendation": "Adopt a naming convention such as kebab-case for directories and camelCase for files, and apply it consistently throughout the project.",
"example": {
"before": "āāā UserServices/\nā āāā userController.js\nā āāā user_model.js\nā āāā user-routes.js",
"after": "āāā user-services/\nā āāā userController.js\nā āāā userModel.js\nā āāā userRoutes.js"
}
}
]
}