stealthy-require review
stealthy-require 1.1.1 temporarily empties Node's process-wide CommonJS cache so one synchronous callback can load a fresh module graph. It then deletes the newly loaded JavaScript entries and copies the previous cache back; an optional second callback preloads dependencies that must remain shared. Version 1.1.1's only code fix stopped `undefined` entries appearing in `require.cache`, and it remains the latest release from May 2017. This is loader-state surgery for legacy CommonJS tests or tooling, not ESM reloading, hot deployment, or per-request isolation.
stealthy-require 1.1.1 installed in 0.3 seconds with 0 dependencies, but any thrown callback can leave the process-wide CommonJS cache unrestored. Keep it only for controlled synchronous legacy tests; use a test runner reset API or child process for code that can fail, load asynchronously, or run concurrently.
We installed it
| Install | ✓ · 0.3s | 1 package on disk · 1 MB |
| Import | ✓ | ESM import works · require() works · CommonJS package |
| Browser | 0.6 KB | gzipped (1.1 KB minified), bundled with esbuild |
| Types | — | no TypeScript types found |
| Known vulns | 0 | 0 critical · 0 high · 0 moderate · 0 low (npm audit) |
Answers from our run
Does stealthy-require install cleanly?
Yes. In a fresh container with an empty cache, npm install stealthy-require finished in 0.3s, leaving 1 package and 1 MB on disk. npm audit reported no known vulnerabilities.
How much does stealthy-require add to a browser bundle?
0.6 KB gzipped (1.1 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.
Does stealthy-require work with both ESM and CommonJS?
Yes. Both import 'stealthy-require' and require('stealthy-require') worked in Node 22 in our run. The package is published as CommonJS.
Does stealthy-require include TypeScript types?
No type declarations were found in our install, so TypeScript users need their own declarations.
stealthy-require or clear-module: which should you use?
clear-module: Use it to evict one named CommonJS module and its descendants rather than snapshotting nearly the whole cache. stealthy-require 1.1.1 installed in 0.3 seconds with 0 dependencies, but any thrown callback can leave the process-wide CommonJS cache unrestored.
When should you not use stealthy-require?
Your code uses ESM or dynamic import(). The package only edits CommonJS require.cache; Node's ESM module map is untouched.
Use it if
- An existing CommonJS test must instantiate one module and all of its synchronous JavaScript dependencies from a clean cache.
- You know which database pools, registries, or other singletons must be preserved through the optional keep callback.
- The load runs in a short-lived process where no other work can require modules concurrently.
- You are maintaining software that already depends on this package's exact snapshot, clear, and restore sequence.
- Your code uses ESM or dynamic `import()`. The package only edits CommonJS `require.cache`; Node's ESM module map is untouched.
- The callback can throw. Version 1.1.1 has no internal `try/finally`, so an error can skip restoration and leave the process cache partly empty or rebuilt.
- Dependencies load later from promises, timers, events, or methods. The README limits fresh loading to synchronous `require()` calls inside the callback.
- Native `.node` addons need fresh instances. The implementation intentionally keeps them cached because loading a native module twice is unsafe.
- A server or concurrent test worker needs isolation. Clearing almost every CommonJS module from global process state cannot be scoped to one request.
- Modern maintenance, types, or bundler support is required. There are no TypeScript declarations, and the last repository push was June 2021.
Setup reality
We installed stealthy-require 1.1.1 in 0.3 seconds in a fresh Node 22 Bookworm sandbox. It left 1 package and 1 MB on disk. npm audit found 0 known vulnerabilities. The package has 0 direct and 0 peer dependencies, is 32 KB unpacked, and declares Node 0.10 or newer. Both CommonJS require() and ESM import loaded, although the package itself is CommonJS with no exports map and contains no TypeScript declarations.
The browser probe measured 1.1 KB minified and 0.6 KB gzipped, but the API still depends on CommonJS cache internals. There are no credentials, native builds, environment variables, or config files. Pass the real require.cache, then perform every fresh require() synchronously inside the callback. The helper snapshots the cache, removes non-.node entries, runs the callback, clears new entries, and restores the original object entries.
That cache is global to the process. Never overlap two calls or run one while other code may load modules. The package has no try/finally; if the load callback or keep callback throws, its restoration steps do not run. An outer cache snapshot can reduce the damage, but a child process is the sound boundary for plugins or unknown code because it also contains globals, timers, native addons, and crashes.
Repeated fresh loads add discarded module objects to the caller's module.children, even after cache restoration. The README tells callers to save and restore that array to avoid retaining every instance. The optional keep callback also requires the caller's module as the fourth argument. Later lazy requires use the restored normal cache. Browserify's documented arguments[5] trick targets version 13.0.1 internals and should not be treated as a current bundler interface.
Patterns
Load a fresh CommonJS dependency tree require-fresh-module
const stealthyRequire = require('stealthy-require');
const freshClient = stealthyRequire(require.cache, () => {
return require('./client');
});Every non-native CommonJS module synchronously required by `./client` loads against the temporarily empty cache, not only the top-level file.
Verify that the original cache is restored compare-fresh-instance
const original = require('./counter');
const fresh = stealthyRequire(require.cache, () => require('./counter'));
const restored = require('./counter');
console.log(original === restored); // true
console.log(original === fresh); // falseThe fresh object is removed from `require.cache` after the call. A later normal require returns the original cached instance.
Keep one dependency cached preserve-singleton-dependency
const freshApp = stealthyRequire(
require.cache,
() => require('./app'),
() => {
require('./database-pool');
require('./metrics-registry');
},
module,
);Both the keep callback and caller's `module` argument are required. Name every singleton whose duplication would be unsafe.
Restore the cache when loading throws restore-cache-after-error
function loadFreshSafely(load) {
const snapshot = { ...require.cache };
try {
return stealthyRequire(require.cache, load);
} finally {
for (const id of Object.keys(require.cache)) delete require.cache[id];
Object.assign(require.cache, snapshot);
}
}
const plugin = loadFreshSafely(() => require('./plugin'));The 1.1.1 implementation can skip restoration after an exception because it has no `try/finally`. This outer snapshot helps, but a child process provides a stronger failure boundary.
Remove discarded modules from module.children avoid-child-retention
const childrenBefore = module.children.slice();
try {
const fresh = stealthyRequire(require.cache, () => require('./worker'));
fresh.run();
} finally {
module.children = childrenBefore;
}Restoring `require.cache` does not remove new entries from `module.children`; save and restore that array during repeated loads.
Read a JSON module without its cached value reload-json-config
const config = stealthyRequire(require.cache, () => {
return require('./settings.json');
});A direct `fs.readFile` plus `JSON.parse` is clearer for configuration and avoids clearing unrelated CommonJS modules.
Create isolated module state in a test reset-module-state-test
it('starts from zero', () => {
const counter = stealthyRequire(require.cache, () => {
return require('../counter');
});
assert.equal(counter.next(), 1);
});Prefer the test runner's module-reset feature when available. This helper reloads the full synchronous dependency graph and repeats initialization side effects.
Keep a native addon outside the fresh graph protect-native-addon
const nativeBinding = require('./build/Release/addon.node');
const freshWrapper = stealthyRequire(
require.cache,
() => require('./wrapper'),
() => require('./build/Release/addon.node'),
module,
);The implementation never deletes `.node` cache entries. The JavaScript wrapper may be fresh while the native binding remains shared.
Use a child process for stronger isolation isolate-in-child-process
const { fork } = require('node:child_process');
const child = fork(require.resolve('./load-plugin-child'), [pluginPath], {
stdio: 'inherit',
});
child.on('exit', (code) => {
if (code !== 0) process.exitCode = code;
});A new process starts with clean loader state and contains native modules, globals, timers, and load errors more reliably than cache edits.
Pass Browserify's legacy cache argument browserify-cache-legacy
const fresh = stealthyRequire(arguments[5], () => {
return require('./feature');
});The README documents `arguments[5]` for Browserify 13.0.1. Generated wrapper arguments are not a portable current bundler API.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| clear-module | npm | Use it to evict one named CommonJS module and its descendants rather than snapshotting nearly the whole cache. |
| import-fresh | npm | Use it for a narrower fresh CommonJS load in configuration scripts or tests. |
| decache | npm | Use it when legacy code only needs to remove a selected module and child entries from the CommonJS cache. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

