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
3 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" } } ] }