Fix Cannot find module errors in Node.js
Trace module resolution failures through paths, dependencies, package exports, and deployment output without discarding a working lockfile.
Start with the missing module named in the error and the module that tried to load it. A resolution failure may concern your entry point, a local file, or a dependency of another package; each points to a different repair.
Check the path from the importing file
const myModule = require('./path/to/myModule.js');
A relative file path begins with ./ or ../. A bare specifier normally refers to a package or built-in module rather than a neighboring file. Compare the exact filename, including case. Filesystem case sensitivity depends on how the filesystem is configured, not just the operating system; deployments often reveal mismatches that a developer's machine tolerated.
For CommonJS, inspect resolution without executing the target module:
console.log(require.resolve('./path/to/myModule.js'));
Run this from the same module location or equivalent context as the failing import. A successful resolution does not prove the module will load successfully or that its own dependencies exist.
Check the dependency declaration and installation
npm ls package-name
Replace package-name with the package reported in the error. Confirm that the consuming project or workspace declares it. If it is genuinely missing from the manifest, add the intended package and version; do not install an arbitrary similarly named package just to silence an error.
For a checkout with a committed, consistent lockfile, npm ci recreates the dependency tree and removes the existing node_modules automatically. Preserve the lockfile. Use npm install when intentionally resolving or updating dependencies, then review the resulting manifest and lockfile changes.
A global installation does not normally satisfy a project's local import. A runtime dependency mistakenly listed only under devDependencies can also disappear from a production install.
Apply the correct module rules
Native ESM requires extensions on relative file imports:
import { add } from './math.js';
A package's exports map may prohibit a deep import even when the file exists. That commonly produces ERR_PACKAGE_PATH_NOT_EXPORTED, which calls for a supported public entry point rather than reinstalling the same package. NODE_PATH affects legacy CommonJS resolution; it is not a general fix for ESM imports.
Compare source and deployed output
Check TypeScript output paths, path aliases, bundler externals, case changes, .dockerignore, and files copied into a container or release artifact. A TypeScript alias needs matching runtime or bundler support; compiler settings alone do not necessarily rewrite it.
@types/* packages provide type declarations, not the corresponding runtime implementation. With pnpm or other stricter dependency layouts, undeclared access to a transitive dependency may stop working. Declare what your package imports directly rather than relying on another package to expose it accidentally.
References
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan