Most Node.js apps can handle more than you think. Here's how to squeeze out real performance gains.
Quick Wins First
1. Enable Compression
import compression from 'compression';
app.use(compression());
Gives you 2-3x throughput improvement instantly.
2. Use Clusters
Node.js runs single-threaded. Use all CPU cores:
import { cluster } from 'node:cluster';
const numCPUs = os.cpus().length;
if (cluster.isPrimary) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
app.listen(3000);
}
3. Database Connection Pooling
Don't open a new DB connection per request. Use a pool:
const pool = new Pool({ max: 20, idleTimeoutMillis: 30000 });
// Reuse connections across requests
Harder Problems
Memory Leaks
Use --inspect and Chrome DevTools to find leaks. Common causes:
- Event listeners not cleaned up
- Global caches growing unbounded
- Closures holding references
N+1 Queries
// Bad: N+1
const users = await db.query('SELECT * FROM users');
for (const user of users) {
user.posts = await db.query('SELECT * FROM posts WHERE user_id = ?', user.id);
}
// Good: Join
const users = await db.query(`
SELECT u.*, p.title as post_title
FROM users u
LEFT JOIN posts p ON u.id = p.user_id
`);
Benchmarking
Always measure before optimizing:
npx autocannon http://localhost:3000/api
Find the actual bottleneck before assuming you know what it is. When debugging Node.js services, ExtensionBooster's developer toolkit includes performance profiling tools.
Top comments (1)
Excellent overview. I'd also recommend monitoring event loop lag and GC activity in production. Sometimes the bottleneck isn't the code itself but memory pressure or long-running synchronous tasks.