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.

Best practices
Illustration of an event loop and asynchronous tasks

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

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting