Node.js · Chapter 43 of 43

Node.js Best Practices

Writing production-quality Node.js apps means more than just making them work — it means structuring code for maintainability, handling errors gracefully, and following security and performance conventions.

Following established best practices makes your app easier to debug, scale, and hand off to other developers.

Code organization

Separate concerns into routes, controllers, models, and services. Keep configuration in environment variables and avoid deeply nested callback code.

Reliability & performance

Always handle errors (sync and async), avoid blocking the event loop with heavy synchronous work, and use logging/monitoring in production.

Example 1 (javascript)
// Good: organized structure
// routes/users.js, controllers/userController.js, models/User.js
const express = require('express');
const router = express.Router();
router.get('/', require('../controllers/userController').list);
module.exports = router;

Splitting routes and controllers keeps large apps maintainable.

Example 2 (javascript)
process.on('unhandledRejection', (reason) => {
  console.error('Unhandled rejection:', reason);
});
Output
Unhandled rejection: Error: ...

Listening for unhandledRejection prevents silent failures from crashing the app unexpectedly.

Key points

  • Organize code into routes, controllers, models, and services.
  • Always handle both sync and async errors.
  • Avoid blocking the event loop with heavy synchronous operations.
  • Use environment variables, logging, and monitoring in production.
💡 Note: Small, focused modules and consistent error handling pay off enormously as an app grows.

📝 Quick Quiz

1. Why separate routes, controllers, and models?

2. What should you avoid doing on the main thread?

3. What event can you listen for to catch unhandled Promise rejections?