How to Fix "Cannot Find Module" Errors in Node.js
Whether Node prints "Cannot find module" or your bundler prints "Module not found", it is the same failure: the resolver can't locate the module. Here is every cause and the exact fix for each, including the two that only break in CI.
Error: Cannot find module 'X' and Module not found: Can't resolve 'X' look like two different problems, but they are the same one wearing two hats. Node's runtime prints the first when its resolver can't find a module you require() or import; a bundler like webpack, Vite, or Next.js prints the second when it can't resolve the same specifier while building your dependency graph. In both cases a resolver was handed a name or a path, went looking for a file, and came back empty-handed. Fix the reason it came back empty and both messages disappear.
How module resolution actually works
Cannot find module is thrown when Node's resolver can't locate the specifier you imported. A specifier starting with ./ or ../ is resolved as a file relative to the current one; a bare specifier like express is looked up in the nearest node_modules. If no matching file exists on disk, resolution fails before any of your code runs.
Everything below is a specific reason that lookup fails. The trick to fixing this error fast is to first ask one question: is the specifier a package (a bare name like lodash) or a file (a relative path like ./utils/format)? Package failures are almost always about installation; file failures are almost always about the path, the extension, or its casing. Read the exact string in quotes in the error — it tells you which branch you're in.
Cause 1: the package isn't installed
The most common cause for a bare specifier: the package simply isn't in node_modules. Either you never ran npm install after cloning, or you imported a package you never added to package.json.
Error: Cannot find module 'axios'
at Function._resolveFilename (node:internal/modules/cjs/loader)
at Module._load (node:internal/modules/cjs/loader)
require('axios') // but axios was never installed# If you just cloned the repo, install everything first
npm install
# If the package is genuinely new, add it
npm install axios
# Confirm it landed in node_modules
npm ls axiosCause 2: a typo or wrong relative path
For a file specifier, the resolver is literal: it joins your path to the current file's directory and looks for exactly that. A misspelled name, a ./ where you needed ../, or a missing segment all resolve to a path that doesn't exist.
// You are in src/components/Card.js and want src/lib/format.js
// Wrong: ./ looks inside src/components, where there is no lib/
import { format } from './lib/format.js';
// Error: Cannot find module './lib/format.js'
// Right: ../ steps up to src/ first
import { format } from '../lib/format.js';When a path looks correct but still fails, print what the resolver is actually looking at. In CommonJS, require.resolve('./lib/format') throws with the resolved path it tried; in any environment, an ls of the directory you think the file is in usually reveals a rename or a wrong folder in seconds. This is the same discipline as reading a stack trace: follow the exact path the tool reports instead of the one you assume is true.
Cause 3: the two gotchas that only break in CI
These are the ones that ruin an afternoon. Your code runs perfectly on your laptop, passes review, and then the CI pipeline or the deployed server throws Cannot find module on a line you never touched. Two causes account for almost all of it.
// File on disk is: src/components/Button.tsx
// Works on macOS/Windows, fails on Linux/CI
import { Button } from './components/button';
// Module not found: Can't resolve './components/button'
// Fix: match the filename's casing exactly
import { Button } from './components/Button';The second gotcha is the missing file extension under native ES modules. Node's ESM resolver, unlike CommonJS, does not try appending .js, .json, or index.js for you — the specifier must name the file exactly. Omit the extension and you get ERR_MODULE_NOT_FOUND, often only when the raw compiled output runs in Node, because your bundler or TypeScript smoothed it over during development.
// In a package with "type": "module", or any .mjs file
// Fails: ESM does not guess the extension
import { parse } from './parser';
// Error [ERR_MODULE_NOT_FOUND]: Cannot find module '.../parser'
// Fix: write the extension explicitly
import { parse } from './parser.js';Cause 4: a missing build step or unconfigured path alias
If you import from a compiled output folder like dist/ but never ran the build, the file the resolver wants doesn't exist yet — run npm run build (or tsc) first. A closely related failure is the path alias: @/lib/format is not a real folder, it's a shorthand that a resolver has to be told how to expand. If the alias is declared in one place but not the one doing the resolving, you get Cannot find module '@/lib/format'.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}The catch: tsconfig paths only teaches the TypeScript compiler and editor about the alias. Your bundler or runtime needs the same mapping in its config — resolve.alias in webpack/Vite, or a jsconfig/loader for plain Node. When an alias resolves in your IDE but throws at build or run time, this mismatch is the reason: the two resolvers don't share the same map.
Cause 5: a stale node_modules or lockfile mismatch
Sometimes the package is in package.json, the path is right, and it still fails — because node_modules is out of sync. A half-finished install, a branch switch that changed dependencies, or a lockfile that no longer matches package.json can all leave a package partially or wrongly installed. The blunt, reliable fix is a clean reinstall.
# Remove the tree and the lockfile, then reinstall from scratch
rm -rf node_modules package-lock.json
npm install
# In CI, prefer a clean, lockfile-exact install
npm ciReach for this after you've ruled out the specific causes above, not before — a clean reinstall fixes a genuinely corrupt tree, but it will happily reinstall a typo or a case-mismatched import and leave you exactly where you started. When the same import also complains that a named export "is not a function", the module resolved but you're reaching for the wrong export shape — a different bug from the module not resolving at all.
When it only fails in production
The hardest variant is a Cannot find module that surfaces only in a deployed environment — a serverless function, a container, an edge runtime — where a native dependency, an optional peer, or a case-sensitive path resolves differently than it did locally. You can't step through it at your desk, and the log line alone rarely tells you which module failed where in the request.
Install the free BugMojo extension and capture the exact session — console, environment, and request context — when a Cannot find module error hits a deployed build, so you fix the real path instead of guessing.
Install the free extensionFrequently asked questions
Frequently asked questions
Sources
- Modules: CommonJS modules — how Node resolves require() through node_modules and relative paths — Node.js (2026)
- Modules: ECMAScript modules — the ESM resolver requires explicit file extensions on relative imports — Node.js (2026)
- import — MDN reference on the static import statement and module specifiers — MDN Web Docs (2026)
- npm-install — installing packages into node_modules so they can be resolved — npm Docs (2026)
Get bug-tracking insights, weekly.
Engineering deep-dives, QA playbooks, and honest tool comparisons. No spam — unsubscribe in one click.

