BugMojoBugMojoBugMojo
FeaturesPricingBlogHelpAbout
Add to ChromeLog inGet started
BugMojoBugMojo

Bug reports that actually help fix bugs — capture, replay, share.

A product of Softech Infra.

Product

  • Features
  • Pricing
  • Browser extension
  • Get started
  • Log in

Resources

  • Help & guides
  • Blog
  • Compare
  • Glossary

Company

  • About
  • Contact
  • Security
  • Privacy
  • Terms
  • Sitemap
© 2026 BugMojo. All rights reserved.
AllGuidesEngineeringPlaybooksCompareGlossaryAlternativesBy roleBug tracking by framework
  1. Home
  2. Blog
  3. Guides
  4. How to Fix "Cannot Find Module" Errors in Node.js
Guide

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.

Hrishikesh BaidyaHrishikesh Baidya·Jul 16, 2026·7 min read
Guides
Isometric line-art console showing a Cannot find module error beside a lime resolved import path, on a dark charcoal canvas
TL;DR
  • What it is: Node's Error: Cannot find module 'X' and a bundler's Module not found: Can't resolve 'X' are the same failure — the resolver can't locate the module.
  • The usual causes: the package isn't installed, a typo in the name, a wrong relative path, a missing ESM file extension, mismatched casing, a missing build step, or an unconfigured path alias.
  • The CI-only gotchas: case-sensitivity (Linux is strict, macOS/Windows aren't) and missing ESM extensions cause "works on my machine" failures that only surface in CI or production.
  • The fixes: install the package, correct the name or path, add the extension, match exact casing, configure the alias, or delete node_modules and reinstall.

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.txttext
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
fix-install.sh
# 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 axios
Tip

If the package installs but is still "not found", check that you didn't add it to devDependencies while running in a production install (npm ci --omit=dev or NODE_ENV=production). Dependencies your runtime imports belong in dependencies, not devDependencies.

Cause 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.

wrong-path.jsjavascript
// 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.

Watch out

Case-sensitivity. macOS and Windows use case-insensitive filesystems, so import './Button' resolves button.tsx without complaint. Linux — which powers virtually every CI runner and production container — is case-sensitive. If the import casing and the filename casing disagree, resolution fails only there. This is the single most common "works on my machine" flavour of this error.

case-mismatch.jsjavascript
// 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.

esm-extension.mjsjavascript
// 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';

To stop case bugs before CI does, turn on "forceConsistentCasingInFileNames": true in tsconfig.json — TypeScript then flags an import whose casing disagrees with the file on disk, locally, at compile time.

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'.

tsconfig.jsonjson
{
  "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.

clean-reinstall.sh
# 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 ci

Reach 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.

Tip

For these deploy-only variants, a captured console plus the environment it ran in is worth more than any amount of local guessing. BugMojo records the exact console error, the runtime, and the request context of the session where it happened — so you see precisely which module and path failed in production, instead of re-deriving it from a single stack line.

Key takeaway

The honest takeaway: Cannot find module and Module not found are one problem — the resolver couldn't find the file. Decide first whether the specifier is a package (fix the install) or a file (fix the path, extension, or casing), and treat any local-only success as a strong hint about case-sensitivity or a missing ESM extension rather than a mysterious CI fluke.

⁓ ⁓ ⁓
See which module failed in production, not just that one did

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 extension

Frequently asked questions

Frequently asked questions

Sources

  1. Modules: CommonJS modules — how Node resolves require() through node_modules and relative paths — Node.js (2026)
  2. Modules: ECMAScript modules — the ESM resolver requires explicit file extensions on relative imports — Node.js (2026)
  3. import — MDN reference on the static import statement and module specifiers — MDN Web Docs (2026)
  4. npm-install — installing packages into node_modules so they can be resolved — npm Docs (2026)
Share:
Hrishikesh Baidya
Hrishikesh Baidya· Chief Technology Officer

Hrishikesh Baidya is the CTO at Softech Infra. He is drawn to architecture that is invisible — systems that simply work — and leads the engineering behind BugMojo.

On this page

  • How module resolution actually works
  • Cause 1: the package isn't installed
  • Cause 2: a typo or wrong relative path
  • Cause 3: the two gotchas that only break in CI
  • Cause 4: a missing build step or unconfigured path alias
  • Cause 5: a stale node_modules or lockfile mismatch
  • When it only fails in production

Get bug-tracking insights, weekly.

Engineering deep-dives, QA playbooks, and honest tool comparisons. No spam — unsubscribe in one click.