# NodeJS Development Rules Essential rules for Node.js backend development. ## Code Style - Use `const` and `let`, never `var` - Use arrow functions for callbacks - Use async/await instead of callbacks - Use template literals for string interpolation - Use object destructuring - Use spread operator for objects/arrays ```javascript // ✅ Good const { id, name } = req.body; const user = { ...req.body, createdAt: new Date() }; const users = await User.findAll(); // ❌ Bad var id = req.body.id; const user = Object.assign({}, req.body, { createdAt: new Date() }); User.findAll().then(users => {}); ``` ## Error Handling - Always use try/catch with async/await - Use centralized error handling middleware - Never catch and swallow errors - Use custom AppError classes - Log errors with context ```javascript // ✅ Good try { const user = await User.findById(id); if (!user) throw new NotFoundError('User'); res.json({ user }); } catch (error) { next(error); } // ❌ Bad User.findById(id).then(user => { if (!user) return res.status(404).json({ error: 'Not found' }); res.json({ user }); }).catch(err => {}); // Swallowing error ``` ## Async Code - Always use async/await - Never mix callbacks and promises - Use Promise.all for parallel operations - Use async middleware wrapper ```javascript // ✅ Good const [users, posts] = await Promise.all([ User.findAll(), Post.findAll() ]); // ❌ Bad let users; User.findAll().then(u => { users = u; }); console.log(users); // undefined ``` ## Security - Always validate and sanitize input - Use parameterized queries - Never expose sensitive data - Use HTTPS in production - Set security headers with helmet - Rate limit public endpoints ```javascript // ✅ Good const user = await db.query('SELECT * FROM users WHERE id = ?', [id]); app.use(helmet()); // ❌ Bad const user = await db.query(`SELECT * FROM users WHERE id = ${id}`); // SQL injection vulnerable ``` ## Authentication - Never store passwords in plain text - Use bcrypt for password hashing - Use short-lived access tokens - Use refresh tokens - Use httpOnly cookies - Never put secrets in JWT payload ```javascript // ✅ Good const hashedPassword = await bcrypt.hash(password, 12); const token = jwt.sign({ id: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' }); // ❌ Bad const hashedPassword = password; // No hash const token = jwt.sign({ password: user.password }, 'secret'); // Secret in payload ``` ## Express Best Practices - Use express.Router() for route organization - Keep route handlers thin - Validate at route level - Put error handlers last - Use middleware for cross-cutting concerns ```javascript // ✅ Good // routes/users.js const router = express.Router(); router.get('/', authenticate, validate, controller.list); // app.js app.use('/api/users', routes.users); app.use(errorHandler); // Last middleware // ❌ Bad app.get('/api/users', async (req, res) => { // All logic in route }); ``` ## Database - Use connection pooling - Close connections gracefully - Use transactions for writes - Index frequently queried fields - Use migrations for schema changes ```javascript // ✅ Good await db.transaction(async (trx) => { await trx('users').insert(user); await trx('profiles').insert(profile); }); // ❌ Bad async function createUser(data) { const user = await db('users').insert(data); // No transaction, partial data on error await Profile.create({ userId: user.id }); } ``` ## Logging - Use structured logging (pino, winston) - Log levels: error, warn, info, debug - Include request ID for tracing - Log errors with stack traces - Don't log sensitive data ```javascript // ✅ Good logger.info({ userId, action: 'login', ip: req.ip }); // ❌ Bad console.log('User logged in:', user); // Logs entire user including password ``` ## Testing - Write tests for critical paths - Use Jest or Mocha - Mock external dependencies - Aim for 80%+ coverage - Test edge cases ```javascript // ✅ Good describe('UserService', () => { it('should create user with hashed password', async () => { const user = await service.create({ email, password }); expect(user.password).not.toBe(password); }); }); ``` ## Environment - Use .env for secrets - Never commit secrets - Use different configs for environments - Validate required env vars ```javascript // ✅ Good const config = { db: { url: process.env.DATABASE_URL } }; if (!config.db.url) { throw new Error('DATABASE_URL is required'); } // ❌ Bad const config = { db: { url: 'postgres://user:pass@localhost/db' // Hardcoded } }; ``` ## Package Management - Use exact versions in production - Run npm audit regularly - Update dependencies regularly - Remove unused dependencies ```bash # ✅ Good npm audit npx depcheck # ❌ Bad # Never running security audit # Many unused dependencies ``` ## Performance - Use streaming for large files - Cache frequently accessed data - Use connection pooling - Implement pagination - Compress responses ```javascript // ✅ Good app.use(compression()); app.get('/users', paginated, controller.list); // ❌ Bad app.get('/users', async (req, res) => { const users = await User.findAll(); // All users at once res.json(users); }); ``` ## Clean Code - No magic numbers, use constants - Meaningful variable names - One function, one responsibility - Comments only for "why", not "what" - DRY principle ```javascript // ✅ Good const MAX_LOGIN_ATTEMPTS = 5; const isLocked = user.loginAttempts >= MAX_LOGIN_ATTEMPTS; // ❌ Bad if (user.loginAttempts >= 5) { // Magic number // ... } ```