Production Best Practices
Learn production best practices for Node.js applications including security, performance, scalability, and maintenance. This is a foundational concept in server-side JavaScript development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Node.js experience. Take your time with each section and practice the examples
security Best Practices
Implement security measures to protect your Node.js applications from common vulnerabilities and attacks.. This is an essential concept that every Node.js developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Input Validation & Sanitization
// Input validation and sanitization
const Joi = require('joi');
const validator = require('validator');
// Validation schemas
const userSchema = Joi.object({
name: Joi.string().min(2).max(50).required(),
email: Joi.string().email().required(),
age: Joi.number().integer().min(0).max(150).optional()
});
// Sanitization middleware
const sanitizeInput = (req, res, next) => {
if (req.body) {
Object.keys(req.body).forEach(key => {
if (typeof req.body[key] === 'string') {
req.body[key] = validator.escape(req.body[key]);
}
});
}
next();
};
// Validation middleware
const validateUser = (req, res, next) => {
const { error } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({
success: false,
error: 'Validation failed',
details: error.details
});
}
next();
};Rate Limiting & DDoS Protection
// Rate limiting and DDoS protection
const rateLimit = require('express-rate-limit');
const slowDown = require('express-slow-down');
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
message: 'Too many requests from this IP',
standardHeaders: true,
legacyHeaders: false
});
// Slow down repeated requests
const speedLimiter = slowDown({
windowMs: 15 * 60 * 1000, // 15 minutes
delayAfter: 50, // allow 50 requests per 15 minutes
delayMs: 500 // add 500ms delay per request after delayAfter
});
// DDoS protection
const ddosProtection = (req, res, next) => {
const ip = req.ip;
const userAgent = req.get('User-Agent');
// Check for suspicious patterns
if (userAgent && userAgent.includes('bot')) {
return res.status(403).json({ error: 'Bot detected' });
}
next();
};Performance Optimization
// Performance optimization techniques
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
// Cluster setup for multi-core utilization
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
cluster.fork(); // Restart worker
});
} else {
// Worker process
const express = require('express');
const app = express();
// Compression middleware
const compression = require('compression');
app.use(compression());
// Caching middleware
const cache = require('memory-cache');
const cacheMiddleware = (duration) => {
return (req, res, next) => {
const key = req.originalUrl;
const cachedBody = cache.get(key);
if (cachedBody) {
return res.send(cachedBody);
} else {
res.sendResponse = res.send;
res.send = (body) => {
cache.put(key, body, duration * 1000);
res.sendResponse(body);
};
next();
}
};
};
app.use(cacheMiddleware(300)); // Cache for 5 minutes
}Monitoring & Health Checks
// Health check and monitoring
const healthCheck = {
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
version: process.env.npm_package_version,
environment: process.env.NODE_ENV
};
// Health check endpoint
app.get('/health', (req, res) => {
res.json(healthCheck);
});
// Detailed health check
app.get('/health/detailed', async (req, res) => {
const health = {
...healthCheck,
database: await checkDatabaseHealth(),
redis: await checkRedisHealth(),
externalServices: await checkExternalServices()
};
res.json(health);
});
async function checkDatabaseHealth() {
try {
// Check database connection
return { status: 'healthy', responseTime: '50ms' };
} catch (error) {
return { status: 'unhealthy', error: error.message };
}
}Mini-Project: Production-Ready App
// Complete production-ready Node.js application
const express = require('express');
const helmet = require('helmet');
const compression = require('compression');
const rateLimit = require('express-rate-limit');
const winston = require('winston');
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
// Logger setup
const logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console());
}
// Cluster setup
if (cluster.isMaster) {
logger.info(`Master ${process.pid} is running`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
logger.error(`Worker ${worker.process.pid} died`);
cluster.fork();
});
} else {
const app = express();
// security middleware
app.use(helmet());
app.use(compression());
// Rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
standardHeaders: true,
legacyHeaders: false
});
app.use(limiter);
// Body parsing
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Request logging
app.use((req, res, next) => {
logger.info('Request', {
method: req.method,
url: req.url,
ip: req.ip,
userAgent: req.get('User-Agent')
});
next();
});
// Routes
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
pid: process.pid
});
});
app.get('/api/status', (req, res) => {
res.json({ status: 'OK', timestamp: new Date().toISOString() });
});
// Error handling
app.use((err, req, res, next) => {
logger.error('Error occurred', {
error: err.message,
stack: err.stack,
url: req.url,
method: req.method
});
res.status(500).json({
error: 'Internal Server Error',
message: process.env.NODE_ENV === 'production'
? 'Something went wrong'
: err.message
});
});
// 404 handler
app.use((req, res) => {
res.status(404).json({ error: 'Not Found' });
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
logger.info(`Worker ${process.pid} started on port ${PORT}`);
});
}
// Graceful shutdown
process.on('SIGTERM', () => {
logger.info('SIGTERM received, shutting down gracefully');
process.exit(0);
});
process.on('SIGINT', () => {
logger.info('SIGINT received, shutting down gracefully');
process.exit(0);
});