nodejs / nodejs/node

module: CJS loader re-stats the same missing paths within one require tree

Open
#64,681 1 comment 0 reactions 1 assignee View on GitHub

@maxday is already working on this.

Since Jul 22, 2026.

module
Dominant language
JavaScript
Stars
122k
Forks
37.3k
Avg merge
4d 2h
Merged PRs (30d)
283

Description

The CommonJS loader keeps a per-require-tree statCache (in lib/internal/modules/cjs/loader.js) to avoid re-stat-ing the same path while resolving a module tree. Today it only caches successful stats. Negative results (e.g. -ENOENT) fall through the cache and are re-probed every time the same missing path is looked up again within the same top-level require.

// lib/internal/modules/cjs/loader.js — stat()
const result = internalFsBinding.internalModuleStat(filename);
if (statCache !== null && result >= 0) {
  // Only set cache when `internalModuleStat(filename)` succeeds.
  statCache.set(filename, result);
}

Failed probes are extremely common during resolution, and the same misses recur across sibling and descendant modules:

  • tryExtensions resolves an extensionless specifier (e.g. require('./helper')) by stat-ing each candidate in order: ./helper.js, then ./helper.json, then ./helper.node until one exists. Every extension tried before the real one is a miss.
  • Bare specifiers (require('foo')) walk the node_modules chain upward: …/a/b/node_modules, …/a/node_modules, …/node_modules. Most of those parent directories don't exist, so each is a negative stat, and every bare require in the tree re-walks the same non-existent ancestors.

Because negatives aren't cached, these misses are re-stat-ed repeatedly within a single resolution pass.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.