Skip to content
DevOps2026-09-083 min read

Cannot find module: 6 Reasons Node.js Can't Find Your Module (and How to Fix Each)

Symptom: two error forms, one root cause

Error: Cannot find module 'express'
Require stack:
- /app/server.js

Or the ESM form:

Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'lodash' imported from /app/index.js

Both mean: Node can't locate the module file you asked it to load. Either the file doesn't exist, the path is wrong, or it's not installed.

Six causes, ranked by frequency

1. Not installed (most common for newcomers)

npm install express

Quick check: ls node_modules/express — does the directory exist?

2. Missing ./ prefix on relative paths

require('utils');       // ❌ Node looks in node_modules for a package named "utils"
require('./utils');     // ✅ relative paths must start with ./ or ../

The rule: any path not starting with ./, ../, or / goes to node_modules.

3. Corrupted node_modules (interrupted install, disk full)

rm -rf node_modules package-lock.json
npm install

Delete-and-reinstall fixes most weirdness — node_modules is ephemeral by design, reinstalling is lossless.

4. Case mismatch (works on macOS, breaks on Linux)

macOS filesystems are case-insensitive by default, so require('./Utils') finds utils.js. Linux (including Docker containers and CI servers) is case-sensitive — works locally, breaks in production is the classic symptom.

# Check actual casing
ls -la src/utils/ | grep -i util

5. ESM/CommonJS mismatch

After adding "type": "module" to package.json, all .js files are parsed as ESM:

| Syntax | CommonJS (.js) | ESM ("type":"module") | |---|---|---| | require('./x') | ✅ | ❌ ERR_MODULE_NOT_FOUND | | import x from './x.js' | ❌ | ✅ (extension required) |

Two key ESM differences: import paths must include the file extension (./utils.js, not ./utils), and bare specifiers without extensions fail.

6. Monorepo / workspace path issues

In a monorepo referencing sibling packages, verify that package.json's workspaces includes the package, and that the import name matches the package's name field exactly.

Why deleting node_modules fixes 80% of cases

node_modules integrity depends on npm install running to completion. A network dropout, Ctrl+C, or disk-full during install can leave a half-installed state — the directory exists but the package's internal package.json (describing its own dependencies) is missing. Reinstalling rebuilds the entire tree, which is faster than surgical repair.

Prevention

  1. Use npm ci in CI instead of npm installci installs strictly from the lock file and errors on mismatch instead of silently resolving
  2. Run a type check before adding skipLibCheck — rules out third-party type errors as a confounder
  3. Use workspace protocol in monorepos ("deps": {"@repo/utils": "workspace:*"}) instead of relative paths

The checklist

  1. ls node_modules/<package> — does the directory exist?
  2. Check path starts with ./ (relative import)
  3. rm -rf node_modules && npm install — reinstall
  4. Case sensitivity check (works locally → breaks on deploy = likely this)
  5. "type": "module" check — does require vs import match the project type?

Provided by ToolVault. Related: Linux Cheatsheet, npm mirror guide, ERESOLVE conflicts. See the homepage for more developer tools.


Advertisement