Optimizing Node.js Functions with Lodash _.memoize: A Practical Guide
Learn how to use Lodash’s _.memoize to cache expensive function results in Node.js. This guide covers prerequisites, a step‑by‑step implementation, validation checks, and recovery strategies to keep your cache healthy.
24 Jun 2026, 11:50 UTC

Desired Outcome
Reduce the runtime of a pure, expensive function by caching its results so that identical input arguments return a stored value instead of recomputing.
Prerequisites
- Node.js 14+ (or any version that supports ES6 modules)
- lodash installed:
npm install lodash - Understanding of pure functions: functions that return the same output for the same input and have no side‑effects.
- Basic knowledge of JavaScript objects and Maps.
Focused Procedure
- Define the expensive function. For illustration, we’ll use a CPU‑heavy Fibonacci calculation.
- Wrap it with _.memoize. Provide an optional resolver if you need custom cache keys.
- Replace calls in your code with the memoized version.
- Validate that caching works. Use a counter or timing checks.
- Implement recovery. Clear the cache or swap to a custom cache if memory grows.
Step 1: Define the Expensive Function
// fibonacci.js
const counter = { calls: 0 };
function fib(n) {
counter.calls++;
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
module.exports = { fib, counter };
Step 2: Wrap with _.memoize
// memoizedFib.js
const _ = require('lodash');
const { fib, counter } = require('./fibonacci');
// Default resolver uses the first argument as the key.
const memoizedFib = _.memoize(fib);
module.exports = { memoizedFib, counter };
Step 3: Use the Memoized Function
// app.js
const { memoizedFib, counter } = require('./memoizedFib');
const start = Date.now();
console.log('Result:', memoizedFib(35)); // first call – computes
console.log('Calls:', counter.calls, 'Time:', Date.now() - start, 'ms');
const start2 = Date.now();
console.log('Result:', memoizedFib(35)); // cached – should be near 0 ms
console.log('Calls:', counter.calls, 'Time:', Date.now() - start2, 'ms');
Step 4: Validate Caching Works
- Check
counter.callsremains 1 after the second invocation. - Use
console.timeto compare execution times:
console.time('first');
memoizedFib(35);
console.timeEnd('first');
console.time('second');
memoizedFib(35);
console.timeEnd('second');
The “second” timer should be significantly lower, indicating a cache hit.
Step 5: Recovery – Clearing or Customizing the Cache
- Clear the entire cache:
memoizedFib.cache.clear();– useful if the data becomes stale or you want to free memory. - Custom cache implementation: Pass a third argument to
_.memoizeto use aMapinstead of the defaultWeakMapwhen keys are not objects.
const customCache = new Map();
const memoizedFibWithMap = _.memoize(fib, undefined, customCache);
Expected Checks
- Ensure the function is pure; otherwise cached results may be incorrect.
- Verify that the cache size does not grow unchecked. For large inputs, inspect
memoizedFib.cache.sizeif using aMap. - Run the memoized function in a loop and confirm that the counter stops incrementing after the first call.
Recovery Options
- Cache Eviction: Lodash’s default
WeakMapautomatically discards entries when keys are garbage‑collected. If you switch to aMap, implement your own eviction policy (e.g., LRU). - Memory Leak Prevention: If you notice memory growth, periodically clear or prune the cache.
- Version Compatibility: Lodash 4.x supports
_.memoizewith a resolver and custom cache. Verify the version by runningnpm list lodash.
Limitations & Caveats
- Memoization only works for pure functions. If the function reads or writes external state, caching can return stale or incorrect data.
- Mutable arguments (objects, arrays) are serialized by reference. Two different objects with the same content will produce separate cache entries.
- The default
WeakMapcannot be inspected for size, making it harder to monitor growth. Use aMapif you need visibility. - Large cached objects can consume significant memory. Consider serializing or pruning heavy results.
- When using custom resolvers, ensure they produce unique keys for distinct argument sets to avoid collisions.
Conclusion
By wrapping expensive pure functions with Lodash’s _.memoize, you can dramatically reduce computation time on repeated calls. Validate cache hits with counters or timing, and keep an eye on memory usage. When the cache becomes stale or too large, clear it or implement a custom eviction strategy. This approach keeps your Node.js application fast and predictable without compromising correctness.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.