V8 normally decides when garbage collection is useful, and that is the right behavior for ordinary Node.js applications. Manually requesting a collection is rarely a production optimization: it pauses JavaScript execution, may reduce throughput, and does not fix retained references or memory leaks.
Current status: Manual garbage collection is still available in Node.js, but it is usually unnecessary. The interface is an experimental V8 extension and is most useful for controlled benchmarks, memory-leak tests, or batch programs with a known idle phase.
Expose the Garbage Collector
Node.js does not expose the collector by default. Start the process with the V8 flag:
node --expose-gc app.js This adds gc() to globalThis. Without the flag, the property is normally undefined.
Request a Collection Safely
function forceGarbageCollection() {
if (typeof globalThis.gc !== "function") {
return false;
}
globalThis.gc();
return true;
}
if (!forceGarbageCollection()) {
console.warn("GC is unavailable; start Node.js with --expose-gc");
} The return value distinguishes an unavailable hook from a completed call. The request is synchronous from the caller's perspective, so it should never run on every request, timer tick, or allocation cycle.
When a Manual Collection Is Useful
- Memory regression tests: release references, request collection, and then count or inspect the surviving objects.
- Benchmarks: reduce unrelated heap state between isolated samples, while keeping the collection itself outside the timed section.
- Batch workloads: request collection during a measured idle phase after a large, temporary data set becomes unreachable.
Even in these cases, measure the result. A lower heapUsed value does not guarantee lower resident memory, because V8 may retain heap pages for later allocations and Node.js also uses native and external memory.
Measure Before and After
function heapUsedInMiB() {
return process.memoryUsage().heapUsed / 1024 / 1024;
}
console.log("before:", heapUsedInMiB().toFixed(1), "MiB");
// Remove all application references to the temporary data first.
globalThis.gc?.();
console.log("after:", heapUsedInMiB().toFixed(1), "MiB"); This only measures JavaScript heap usage. For diagnosis, process.memoryUsage() also reports resident-set, external, and array-buffer memory. Node.js additionally provides heap snapshots, heap profiles, --trace-gc, and the node:v8 GC profiler. Those tools usually reveal more than repeatedly forcing collections.
What Manual GC Does Not Solve
Garbage collection only reclaims unreachable objects. If a cache, event listener, timer, closure, or global collection still references an object, calling gc() cannot release it. A steadily growing post-collection baseline therefore points to retained data and should be investigated with snapshots or allocation profiles.
The --expose-gc flag and the exact behavior of the exposed function belong to V8 rather than the stable JavaScript language API. Keep the hook optional, do not make application correctness depend on it, and re-check Node.js release notes before relying on it in long-lived tooling.