Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
247 changes: 247 additions & 0 deletions backend/nodejs/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
---
description: Vibe coding guidelines and architectural constraints for Node.js within the backend domain.
technology: Node.js
domain: backend
level: Senior/Architect
version: "24+"
tags: [best-practices, clean-code, architecture-patterns, vibe-coding, cursor-rules, javascript, typescript, software-architecture, system-design, solid-principles, production-ready, programming-standards, node-js, design-patterns, scalable-code, windsurf-rules, ai-coding, fsd, ddd, enterprise-patterns]
ai_role: Senior Node.js Architecture Expert
last_updated: 2026-03-23
---

<div align="center">
<img src="https://raw.githubusercontent.com/tandpfun/skill-icons/main/icons/NodeJS-Dark.svg" width="100" alt="Node.js Logo">

# 🟢 Node.js Production-Ready Best Practices
</div>

---

This document establishes **best practices** for building and maintaining Node.js applications. These constraints guarantee a scalable, highly secure, and clean architecture suitable for an enterprise-level, production-ready backend.

# ⚙️ Context & Scope
- **Primary Goal:** Provide an uncompromising set of rules and architectural constraints for pure Node.js environments.
- **Target Tooling:** AI-agents (Cursor, Windsurf, Copilot, Antigravity) and Senior Developers.
- **Tech Stack Version:** Node.js 24+

> [!IMPORTANT]
> **Architectural Contract:** Code must be completely asynchronous. Absolutely avoid synchronous blocking methods like `readFileSync` or `crypto.pbkdf2Sync` on the main thread. Delegate heavy computational tasks to Worker Threads or separate microservices to keep the event loop non-blocking.

---

## 🏗️ Architecture & Component Isolation

Node.js applications must use explicit module separation to handle logic appropriately.

```mermaid
graph TD
A["🟢 HTTP Server / Entry Point"] --> B["🔌 Controllers / Routing"]
B --> C["⚙️ Service Layer (Business Logic)"]
C --> D["🗄️ Data Access Layer (Repositories)"]
D --> E["💾 Database / Cache"]

%% Added Design Token Styles for Mermaid Diagrams
classDef default fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px,color:#000;
classDef component fill:#e8f5e9,stroke:#4caf50,stroke-width:2px,color:#000;
classDef layout fill:#f3e5f5,stroke:#9c27b0,stroke-width:2px,color:#000;

class A layout;
class B component;
class C component;
class D component;
class E layout;
```

---

## 1. ⚡ Blocking the Event Loop
### ❌ Bad Practice
```javascript
const crypto = require('crypto');
app.post('/hash', (req, res) => {
const hash = crypto.pbkdf2Sync(req.body.password, 'salt', 100000, 64, 'sha512'); // Blocks the whole server
res.send(hash);
});
```
### ✅ Best Practice
```javascript
const crypto = require('crypto');
app.post('/hash', (req, res, next) => {
crypto.pbkdf2(req.body.password, 'salt', 100000, 64, 'sha512', (err, derivedKey) => {
if (err) return next(err);
res.send(derivedKey.toString('hex'));
});
});
```
### 🚀 Solution
Never use synchronous methods (`*Sync`) on the main thread for crypto, I/O, or heavy calculations. Always use asynchronous callbacks or Promises to prevent blocking the Event Loop.

## 2. 🗂️ Project Structure & Module Separation
### ❌ Bad Practice
```text
/server.js (Contains routes, DB connections, and logic all in one 1500-line file)
```
### ✅ Best Practice
```text
/src
/api (Controllers and routes)
/services (Business logic)
/models (Database schemas)
/config (Environment and configurations)
/utils (Helper functions)
```
### 🚀 Solution
Implement a multi-layered folder architecture. Strictly separate the HTTP transport layer (Routes/Controllers) from the Business Logic (Services) and Database operations.

## 3. 🛡️ Strict Environment Configuration
### ❌ Bad Practice
```javascript
const port = process.env.PORT || 3000;
// Continuing application startup without validating required variables.
```
### ✅ Best Practice
```javascript
const requiredEnv = ['DATABASE_URL', 'JWT_SECRET', 'PORT'];
requiredEnv.forEach((name) => {
if (!process.env[name]) {
console.error(`Environment variable ${name} is missing.`);
process.exit(1);
}
});
```
### 🚀 Solution
Fail fast. Validate all necessary environment variables upon application startup to prevent fatal runtime errors later in execution.

## 4. 🛑 Error Handling with Custom Classes
### ❌ Bad Practice
```javascript
if (!user) throw new Error('User not found');
```
### ✅ Best Practice
```javascript
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true; // Distinguish between operational and programming errors
}
}
if (!user) throw new AppError('User not found', 404);
```
### 🚀 Solution
Extend the built-in `Error` object to create custom operational errors. This allows your global error handler to safely log and return predictable HTTP status codes without crashing the application.

## 5. 🎛️ Handling Uncaught Exceptions & Rejections
### ❌ Bad Practice
// Ignoring process-level events, allowing the app to run in an unpredictable state after an error.
### ✅ Best Practice
```javascript
process.on('uncaughtException', (err) => {
logger.error('UNCAUGHT EXCEPTION! Shutting down...', err);
process.exit(1);
});

process.on('unhandledRejection', (err) => {
logger.error('UNHANDLED REJECTION! Shutting down...', err);
server.close(() => process.exit(1));
});
```
### 🚀 Solution
Always capture `uncaughtException` and `unhandledRejection`. Log the fatal error immediately and shut down the process safely. Rely on a process manager (like PM2 or Kubernetes) to restart the container.

## 6. 🔒 Hiding Sensitive Headers
### ❌ Bad Practice
// Sending default headers that expose the framework, like `X-Powered-By: Express`.
### ✅ Best Practice
```javascript
// Example using Express + Helmet, but applies generically to HTTP responses
const helmet = require('helmet');
app.use(helmet());
```
### 🚀 Solution
Sanitize outgoing HTTP headers to prevent information leakage about the server infrastructure.

## 7. ⏱️ Implementing Graceful Shutdown
### ❌ Bad Practice
// Application crashes abruptly during deployments, interrupting active user requests and corrupting database transactions.
### ✅ Best Practice
```javascript
process.on('SIGTERM', () => {
console.info('SIGTERM signal received. Closing HTTP server.');
server.close(() => {
console.log('HTTP server closed.');
mongoose.connection.close(false, () => {
console.log('Database connection closed.');
process.exit(0);
});
});
});
```
### 🚀 Solution
Listen for termination signals (`SIGTERM`, `SIGINT`). Finish processing ongoing HTTP requests and safely close database connections before exiting the Node.js process.

## 8. 🔍 Input Validation and Sanitization
### ❌ Bad Practice
```javascript
// Blindly trusting user input
const user = await db.query(`SELECT * FROM users WHERE email = '${req.body.email}'`);
```
### ✅ Best Practice
```javascript
// Utilizing parameterized queries and a validation library like Joi or Zod
const schema = Joi.object({ email: Joi.string().email().required() });
const { error, value } = schema.validate(req.body);

if (error) throw new AppError('Invalid input', 400);
const user = await db.query('SELECT * FROM users WHERE email = $1', [value.email]);
```
### 🚀 Solution
Never trust external data. Validate input strictly using schema definitions and always utilize parameterized queries or an ORM to prevent SQL/NoSQL Injection attacks.

## 9. 🚀 Utilizing Worker Threads for Heavy Tasks
### ❌ Bad Practice
```javascript
// Processing a massive image buffer directly on the main event loop
function processImage(buffer) {
// heavy sync computation taking 500ms...
}
```
### ✅ Best Practice
```javascript
const { Worker } = require('worker_threads');

function processImageAsync(buffer) {
return new Promise((resolve, reject) => {
const worker = new Worker('./imageProcessor.js', { workerData: buffer });
worker.on('message', resolve);
worker.on('error', reject);
});
}
```
### 🚀 Solution
Offload CPU-intensive operations (image processing, video encoding, heavy cryptographic tasks) to Node.js `worker_threads` to keep the primary event loop highly responsive for API requests.

## 10. 📝 Centralized and Structured Logging
### ❌ Bad Practice
```javascript
console.log('User logged in', userId);
```
### ✅ Best Practice
```javascript
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [new winston.transports.Console()],
});

logger.info('User logged in', { userId, timestamp: new Date().toISOString() });
```
### 🚀 Solution
Avoid `console.log`. Use a sophisticated logging library (like Pino or Winston) to generate structured, JSON-formatted logs that are easily ingested by external monitoring systems (Datadog, ELK).

<br>

<div align="center">
<b>Enforce these Core Node.js constraints to ensure a highly scalable, stable, and performant backend system! 🟢</b>
</div>
1 change: 1 addition & 0 deletions backend/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ last_updated: 2026-03-22
This folder acts as a container for documentation around the following backend technologies:
- [NestJS](./nestjs/readme.md)
- [ExpressJS](./expressjs/readme.md)
- [Node.js](./nodejs/readme.md)
Loading