A memory leak in Node.js happens when memory is allocated but not released, and over time the app starts consuming more and more RAM, eventually slowing down or crashing.
Common situations where memory leaks happen
1. Unused Global Variables
If variables are stored globally, they stay in memory for the lifetime of the app.
let users = [];
app.get("/add", (req, res) => {
users.push({ name: "user" }); // keeps growing
res.send("Added");
});
👉 Problem: Array keeps growing → memory never freed
2. Closures Holding References
Closures can unintentionally keep variables alive.
function outer() {
let largeData = new Array(1000000).fill("data");
return function inner() {
console.log("Using data");
};
}
👉 Even if not used, largeData stays in memory because of closure
3. Event Listeners Not Removed
Adding listeners repeatedly without removing them can cause leaks.
const EventEmitter = require("events");
const emitter = new EventEmitter();
setInterval(() => {
emitter.on("event", () => {
console.log("Triggered");
});
}, 1000);
👉 New listener added every second → memory increases
4. setInterval / Timers Not Cleared
Uncleared timers keep running forever.
setInterval(() => {
console.log("Running...");
}, 1000);
👉 If not cleared when not needed → memory + CPU usage increases
5. Caching Too Much Data
Storing large data in memory (cache) without limits.
const cache = {};
app.get("/data", (req, res) => {
cache[Date.now()] = new Array(100000).fill("data");
res.send("Stored");
});
👉 Cache keeps growing → no cleanup
6. Improper Handling of Streams / Buffers
Not closing streams properly can hold memory.
Example:
- File streams not closed
- Large buffers kept in memory
7. Circular References
Objects referencing each other may not be garbage collected.
let obj1 = {};
let obj2 = {};
obj1.ref = obj2;
obj2.ref = obj1;
👉 GC may struggle if references are still reachable
8. Memory Leaks in Third-party Libraries
Sometimes leaks are caused by:
- Poorly written npm packages
- Bugs in dependencies
How to Detect Memory Leaks
- Use tools like:
- Chrome DevTools (heap snapshots)
node --inspectclinic.js
- Monitor memory usage over time
Best Practices to Avoid Memory Leaks
- Avoid unnecessary global variables
- Remove event listeners (
removeListener) - Clear timers (
clearInterval) - Limit cache size (use LRU cache)
- Use streams instead of loading large data in memory
- Regularly monitor memory
Real-world Scenario
Example:
- Logging system stores logs in an array
- Array grows continuously
- Server memory increases → app crashes after some time
Key Takeaway
Memory leaks happen when objects are still referenced and cannot be garbage collected. In Node.js, this usually occurs due to uncontrolled data growth, uncleaned listeners/timers, or improper resource handling, so always manage memory carefully in long-running applications.