Building Scalable Node.js Applications
March 20, 2024
12 min read
BackendIntroduction
Node.js has become a popular choice for building scalable server-side applications. However, building production-ready applications requires careful planning and best practices.
Architecture Patterns
MVC Pattern
// Model
class User {
constructor(id, name, email) {
this.id = id;
this.name = name;
this.email = email;
}
}
// Controller
class UserController {
getUser(req, res) {
// Business logic
}
}
// Routes
app.get('/users/:id', userController.getUser);
Microservices Architecture
When your application grows, consider splitting into microservices:
┌─────────────┐ ┌──────────────┐ ┌───────────────┐
│ API Gateway │─────▶│ User Service │ │ Product Service
└─────────────┘ └──────────────┘ └───────────────┘
│
▼
┌──────────────┐
│ Database │
└──────────────┘
Performance Optimization
Caching Strategy
const redis = require('redis');
const client = redis.createClient();
async function getCachedUser(userId) {
const cached = await client.get(`user:${userId}`);
if (cached) {
return JSON.parse(cached);
}
const user = await fetchUserFromDB(userId);
await client.setex(`user:${userId}`, 3600, JSON.stringify(user));
return user;
}
Connection Pooling
const pool = mysql.createPool({
connectionLimit: 10,
host: 'localhost',
user: 'user',
password: 'password',
database: 'mydb'
});
Error Handling
Centralized Error Handler
app.use((err, req, res, next) => {
console.error(err.stack);
const status = err.status || 500;
const message = err.message || 'Internal Server Error';
res.status(status).json({
status,
message,
error: process.env.NODE_ENV === 'development' ? err : {}
});
});
Monitoring and Logging
Winston Logger
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
logger.info('Server started');
Database Optimization
Query Optimization
- Use indexes on frequently queried columns
- Avoid N+1 queries with proper joins
- Implement query caching
Pagination
async function getPaginatedUsers(page = 1, limit = 20) {
const offset = (page - 1) * limit;
return await User.findAndCountAll({
limit,
offset,
order: [['createdAt', 'DESC']]
});
}
Security Best Practices
- Use environment variables for secrets
- Implement rate limiting
- Validate and sanitize all inputs
- Use HTTPS in production
- Implement proper authentication
Deployment
PM2 Process Manager
pm2 start app.js -i max
pm2 start app.js --watch
pm2 logs
Conclusion
Building scalable Node.js applications requires attention to architecture, performance, and security. Follow these patterns and best practices to create robust production applications.
#nodejs#backend#architecture#scalability
Author
Kirtan kalathiya
Full-stack developer passionate about creating exceptional web experiences. Sharing knowledge about web development, design, and technology.
💬 Discussion
Share your thoughts and insights about this article. Have questions? Let's discuss in the comments.