mrkeyoor.com_
Sat 08 Aug 21:00 UTC
npmUtilsupdated 08 Aug 2026

stealthy-require

stealthy-require is a small CommonJS cache-manipulation helper. It snapshots `require.cache`, removes every cached JavaScript module, runs your synchronous callback so its `require()` calls create fresh module instances, removes those new cache entries, and restores the original cache. An optional callback can preload selected dependencies that should stay cached. It affects the process-wide CommonJS loader, not ECMAScript module imports.

Verdict

Do not use this as hot reload or general test isolation. It is acceptable only in controlled legacy CommonJS code where loads are synchronous, errors are contained, and process-wide cache mutation is understood.

API stability4/5The package exposes one function with the same four positional arguments since 1.1.0, and 1.1.1 only fixed an undefined-cache-entry bug. Its tiny surface is unlikely to drift, but the contract is coupled to undocumented loader state, positional optional callbacks, and caller-supplied `module`, so runtime stability is weaker than signature stability.
Docs4/5The README is unusually candid about native addon limits, synchronous-only bypassing, dependency preservation, Browserify handling, process cache steps, and the `module.children` memory retention problem, with concrete examples. It fails to warn that thrown callbacks skip cache restoration, and it has no ESM, modern bundler, concurrency, or TypeScript guidance.
Maintenance1/5npm lists 1.1.1 from May 2017 as the latest release, and GitHub reports the last repository push in June 2021. The package is not archived or deprecated and its zero-dependency code is small, but the unresolved lack of exception-safe restoration and absence of ESM-era updates mean it should be treated as dormant.
Ecosystem2/5The package recorded 4,241,886 downloads in the measured week, almost certainly reflecting transitive use, yet the repository has only 22 stars and the tool offers no integrations beyond legacy CommonJS and old bundler recipes. Modern test frameworks, ESM loaders, worker isolation, and application module systems do not share its cache model.

Use it if

  • You maintain a legacy CommonJS test suite that must instantiate a module and its dependency tree from scratch
  • You know the complete synchronous require graph and need selected singleton dependencies preserved
  • You are debugging module initialization and can run the load in an isolated short-lived process
  • You are supporting an existing package that already depends on this exact cache restoration behavior
Skip it if

Setup reality

Installation is `npm install stealthy-require`; it has no runtime dependencies, native build of its own, peers, credentials, or config files. Its entire contract depends on CommonJS internals. You must pass the actual `require.cache` object plus a synchronous callback that performs and returns the desired `require()`. The helper snapshots the whole cache, deletes every entry whose filename does not end in `.node`, executes the callback, clears again, and copies the old entries back. This is process-wide mutable state, not a per-module sandbox. Do not overlap calls, invoke it while other code is loading modules, or treat it as request-safe hot reload. The most serious implementation surprise is error handling: neither callback is protected by `try/finally`. If loading throws, restoration code is skipped and subsequent requires can create unexpected duplicate singletons. Wrap calls with your own cache snapshot and restoration or, better, isolate risky loads in a child process. Fresh modules are also appended to the caller's `module.children`; the README shows snapshotting and restoring that array to avoid retaining every discarded instance. The optional keep callback needs the caller's `module` object as a fourth argument and must synchronously require every module to preserve. Native addons always remain cached, while lazy requires after the main callback return use the normal restored cache. There are no TypeScript declarations or ESM exports. The Webpack and Browserify instructions target old bundler internals, including Browserify's sixth wrapper argument, and should not be assumed to work in modern bundlers. In application code, module factories, explicit dependency injection, test-runner module reset features, or a new child process are safer designs.

Patterns

Load a fresh CommonJS dependency treerequire-fresh-module

const stealthyRequire = require('stealthy-require');

const freshClient = stealthyRequire(require.cache, () => {
  return require('./client');
});

Every non-native CommonJS module synchronously required by `./client` is loaded against an empty cache, not only the top-level module.

Verify that the original cache is restoredcompare-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); // false

The fresh instance is deliberately absent from `require.cache` after the call, while the original instance is copied back.

Keep one dependency cachedpreserve-singleton-dependency

const freshApp = stealthyRequire(
  require.cache,
  () => require('./app'),
  () => {
    require('./database-pool');
    require('./metrics-registry');
  },
  module,
);

The keep callback and caller's `module` argument are both required for this mode. List every singleton that must not be duplicated.

Restore the cache when loading throwsrestore-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'));

Version 1.1.1 has no internal `try/finally`. This outer guard is necessary when the callback can throw, though a child process gives stronger isolation.

Remove discarded modules from module.childrenavoid-child-retention

const childrenBefore = module.children.slice();
try {
  const fresh = stealthyRequire(require.cache, () => require('./worker'));
  fresh.run();
} finally {
  module.children = childrenBefore;
}

Cache restoration does not remove fresh instances from the caller's `module.children`; repeated loads retain memory unless that array is restored.

Read a JSON module without its cached valuereload-json-config

const config = stealthyRequire(require.cache, () => {
  return require('./settings.json');
});

This reloads CommonJS JSON modules, but direct `fs.readFile` plus `JSON.parse` is clearer and avoids clearing unrelated modules.

Create isolated module state in a testreset-module-state-test

it('starts from zero', () => {
  const counter = stealthyRequire(require.cache, () => {
    return require('../counter');
  });

  assert.equal(counter.next(), 1);
});

Use the test runner's built-in module reset when available. This helper resets the complete synchronous dependency tree and can duplicate global side effects.

Keep a native addon outside the fresh graphprotect-native-addon

const nativeBinding = require('./build/Release/addon.node');

const freshWrapper = stealthyRequire(
  require.cache,
  () => require('./wrapper'),
  () => require('./build/Release/addon.node'),
  module,
);

`.node` cache entries are never deleted by the implementation. The wrapper can be fresh, but the native binding remains the existing instance.

Use a child process for stronger isolationisolate-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;
});

This does not call stealthy-require because a new process has a clean module cache and contains native modules, globals, timers, and load failures more reliably.

Pass Browserify's legacy cache argumentbrowserify-cache-legacy

const fresh = stealthyRequire(arguments[5], () => {
  return require('./feature');
});

The README documents this for Browserify 13.0.1. It relies on generated wrapper internals and is not a portable modern bundler API.

Alternatives

PackageRegistryPick it when
clear-modulenpmYou want to evict one CommonJS module and its descendants explicitly instead of snapshotting the entire cache
import-freshnpmYou want a small helper that returns a fresh CommonJS import for configuration or test code
decachenpmYou need a simple legacy API to remove a named module and its children from the CommonJS cache