Node.js Error

Error: Cannot find module

error code: MODULE_NOT_FOUND

Complete reference — what it means, every cause, and how to fix it.

Quick Answer: Node.js throws Error: Cannot find module '...' (code: MODULE_NOT_FOUND) when require() cannot locate the requested file or package. The most common fix is running npm install if you just cloned a repo, or checking for a typo in the module name or file path.

What is "Error: Cannot find module"?

Error: Cannot find module '...' is the most frequently encountered Node.js error. It is thrown by the CommonJS module loader whenever require() cannot resolve the string you passed — whether that is an npm package name, a relative file path, or a built-in module alias that does not exist. The error object carries the code MODULE_NOT_FOUND.

Exact error messages you will see:
Error: Cannot find module 'express'
Error: Cannot find module './utils'
Error: Cannot find module '@/components/Button'
Error: Cannot find module './config.json'
Error: Cannot find module './models'

Full Error Example

node:internal/modules/cjs/loader:1039
    throw err;
    ^

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

    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1039:15)
    at Function.Module._load (node:internal/modules/cjs/loader:885:27)
    at Module.require (node:internal/modules/cjs/loader:1105:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at Object.<anonymous> (/project/app.js:1:17) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [ '/project/app.js' ]
}

The Require stack field (added in Node.js 12) shows the chain of files that triggered the failing require(), which is invaluable for tracing the source of the error in large projects.

Root Cause

When you call require('some-module'), Node.js runs its module resolution algorithm:

  1. If the string starts with ./, ../, or / — resolve as a file path relative to the current file.
  2. Otherwise — walk up node_modules/ directories starting from the current file's location.
  3. If nothing is found at any step — throw MODULE_NOT_FOUND.

The error fires whenever the algorithm reaches the end of its search without finding a match.

All Causes at a Glance

CauseTypical symptomQuick fix
Dependencies not installed Cannot find module 'express' after cloning npm install
Typo in module name Cannot find module 'loadash' Fix the spelling in require()
Wrong relative path Cannot find module './utils' (wrong directory level) Adjust ./ / ../ prefix
Missing file extension Cannot find module './config' for a JSON file Use require('./config.json')
Missing index.js Cannot find module './models' (directory import) Create models/index.js
Global-only install Cannot find module 'typescript' (installed with -g) npm install typescript locally
devDependency in production Works locally, fails on server Move to dependencies
ESM-only package with require() Cannot find module 'chalk' (chalk@5+) Use await import('chalk') or downgrade
Case sensitivity on Linux Works on macOS/Windows, fails on Linux/CI Match filename case exactly
Corrupted node_modules Package appears installed but error persists rm -rf node_modules && npm install
TypeScript path aliases Cannot find module '@/utils' at runtime Register tsconfig-paths
Docker — no local install Cannot find module 'express' in container Run npm install in Dockerfile
Wrong working directory Script runs from wrong directory cd to project root first
Broken symlinks Error after linking packages or using workspaces rm -rf node_modules && npm install

Common Causes & Fixes

Cause 1 – Dependencies not installed

The most frequent cause: you cloned a repo or switched branches and node_modules is missing or out of date.

# Install all dependencies listed in package.json
npm install

# Or with yarn / pnpm
yarn install
pnpm install
Commonly affected packages: express, dotenv, axios, lodash, typescript, @prisma/client, react, next, jest — any package will trigger this if node_modules is absent.

Cause 2 – Typo in the module name

npm package names are case-sensitive and exact. A single character difference silently produces this error.

// Wrong
const express = require('Express');   // capital E
const lodash  = require('loadash');   // missing 'd'

// Correct
const express = require('express');
const lodash  = require('lodash');

Cause 3 – Wrong relative path

Relative paths are resolved from the current file's location, not the project root.

// File: /project/src/routes/users.js
// Trying to import /project/src/utils.js

// Wrong – resolves to /project/src/routes/utils.js (not found)
const utils = require('./utils');

// Correct
const utils = require('../utils');

Use console.log(__dirname) or path.resolve('./utils') to debug the resolved path at runtime.

const path = require('path');
console.log(path.resolve('./utils')); // prints the full path Node.js will look up

Cause 4 – Missing file extension for non-JS files

Node.js automatically tries .js, .json, and .node extensions when resolving bare filenames — but only in that order and only when no extension is given for a relative path. In practice, omitting the extension for .json files can silently fail in certain configurations or when the file does not exist with the expected name.

// Wrong – may throw MODULE_NOT_FOUND if resolution fails
const config = require('./config');

// Correct – always explicit for non-JS files
const config = require('./config.json');
const native = require('./bindings.node');

Cause 5 – Missing index.js for directory imports

When you require('./models') and models is a directory, Node.js looks for models/index.js. If that file does not exist, you get MODULE_NOT_FOUND.

// Directory structure that causes the error:
// models/
//   User.js
//   Post.js
//   (no index.js)

const models = require('./models'); // throws MODULE_NOT_FOUND
// Fix: create models/index.js
const User = require('./User');
const Post = require('./Post');
module.exports = { User, Post };

Cause 6 – Package installed globally, not locally

Running npm install -g express makes express available as a CLI tool but does not make it available to require() inside your project. Node.js searches node_modules/ directories relative to the script — not the global npm prefix.

# This does NOT fix the error
npm install -g express

# This does fix the error
npm install express

# Verify local installation
npm ls express

Cause 7 – Running from the wrong working directory

Node.js resolves bare module names by searching node_modules/ starting from the script's location, but ./ paths are relative to process.cwd(). Running a script from a parent directory changes what ./ resolves to.

# Wrong – running from the parent directory
cd /
node project/src/app.js

# Correct
cd /project
node src/app.js

Always run node from the project root, or use __dirname-based absolute paths in your code.

Cause 8 – Package in devDependencies used in production

npm install --production (or NODE_ENV=production npm install) skips devDependencies. If a package required at runtime lives there, it will be missing in production.

// Move from devDependencies to dependencies in package.json
{
  "dependencies": {
    "dotenv": "^16.0.0"   // ← was incorrectly in devDependencies
  }
}

Cause 9 – ESM-only package loaded with require()

Several popular npm packages dropped CommonJS support and published ESM-only versions. Using require() on these packages throws MODULE_NOT_FOUND or ERR_REQUIRE_ESM (depending on Node.js version).

Common ESM-only packages: chalk@5+, node-fetch@3+, got@12+, ora@6+, p-limit@4+, execa@6+

// Wrong – chalk v5 is ESM-only
const chalk = require('chalk'); // Error: Cannot find module 'chalk'

// Fix option 1 – use dynamic import (works in any .js file)
const chalk = await import('chalk');

// Fix option 2 – downgrade to last CJS version
// npm install chalk@4
const chalk = require('chalk'); // chalk@4 is CJS

// Fix option 3 – convert project to ESM
// Add "type": "module" to package.json and use import syntax
import chalk from 'chalk';

Cause 10 – Case sensitivity on Linux

macOS and Windows filesystems are usually case-insensitive, so require('./Utils') finds utils.js. Linux (including most CI/CD and production servers) is case-sensitive — the same code throws Cannot find module.

// Wrong on Linux (file on disk is utils.js)
const utils = require('./Utils');

// Correct – match the filename exactly
const utils = require('./utils');

Cause 11 – Corrupted or incomplete install

Interrupted installs, disk errors, or npm cache corruption can leave node_modules in a broken state even though the package appears in package.json.

# macOS / Linux – full clean reinstall
rm -rf node_modules package-lock.json
npm install

# Windows (Command Prompt)
rd /s /q node_modules
del package-lock.json
npm install

# Optional: also clear the npm cache
npm cache clean --force
npm install

Cause 12 – TypeScript path aliases not resolved at runtime

TypeScript supports path aliases like @/utils or ~/components defined in tsconfig.json. These are a TypeScript-only feature — the compiled JavaScript still contains the alias string, and Node.js has no idea what @/utils means.

// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  }
}

// your code – works in TypeScript, throws Cannot find module at runtime
import { helper } from '@/utils';

Fix: register tsconfig-paths at runtime to teach Node.js how to resolve the aliases:

# compiled output
node -r tsconfig-paths/register dist/app.js

# with ts-node
ts-node -r tsconfig-paths/register src/app.ts

Alternatively, use a bundler (esbuild, webpack, Vite) that resolves aliases at build time so no runtime registration is needed.

Cause 13 – node_modules not installed inside Docker

A common Docker mistake: installing dependencies on the host machine and then copying the whole project into the image. If node_modules is in .dockerignore (as it should be), dependencies will be missing unless npm install runs inside the container.

# Wrong Dockerfile order
COPY . .
RUN npm install   # too late — node_modules from host was never copied in
# Correct – install before copying source; exploits layer cache too
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "src/app.js"]

Also confirm your .dockerignore includes node_modules so the host modules are never copied into the image.

Cause 14 – Broken symlinks in node_modules

npm workspaces, npm link, and some CI environments create symlinks inside node_modules. If the symlink target no longer exists or the symlink was corrupted, Node.js cannot follow it and throws MODULE_NOT_FOUND.

# Detect broken symlinks (macOS/Linux)
find node_modules -type l ! -exec test -e {} \; -print

# Fix: full reinstall
rm -rf node_modules package-lock.json
npm install

# If using npm workspaces, run from the workspace root
npm install --workspaces

Debugging Techniques

Inspect the module search paths

module.paths is an array of every node_modules directory Node.js will search, in order. Print it to verify Node.js is looking in the right place.

// Add temporarily to the failing script
console.log(module.paths);
// [
//   '/project/src/node_modules',
//   '/project/node_modules',
//   '/node_modules'
// ]

Use require.resolve() to test resolution

try {
  const resolved = require.resolve('express');
  console.log('Found at:', resolved);
} catch (err) {
  console.error('Not found:', err.message);
}

Enable Node.js module debug output

# Prints every path Node.js attempts during resolution
NODE_DEBUG=module node app.js

General debugging checklist

  1. Read the Require stack in the error — it shows exactly which file called require().
  2. Run ls node_modules/<package-name> to confirm the package is physically installed.
  3. Run npm ls <package-name> to see if it is listed as a dependency.
  4. Print __dirname and path.resolve('./your-path') to verify the resolved path.
  5. Print module.paths to see all directories Node.js is searching.
  6. Check package.json — is the package under dependencies or devDependencies?
  7. Confirm the filename on disk matches the case used in require().
  8. In TypeScript projects, check for unresolved path aliases in the compiled output.
  9. In Docker/CI, confirm npm install runs inside the container, not just on the host.
  10. Run NODE_DEBUG=module node app.js to trace every path attempted during resolution.

CJS vs ESM: MODULE_NOT_FOUND vs ERR_MODULE_NOT_FOUND

The MODULE_NOT_FOUND code belongs to the CommonJS (require()) loader. The native ESM (import) loader throws a different error code: ERR_MODULE_NOT_FOUND. The root causes are identical but the error messages look different:

LoaderError codeTypical message
CommonJS (require) MODULE_NOT_FOUND Error: Cannot find module 'x'
ESM (import) ERR_MODULE_NOT_FOUND Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'x'
Common mistake: Deleting only node_modules without also deleting package-lock.json can leave npm in an inconsistent state. Always delete both before a clean reinstall.

Frequently Asked Questions

What does "Error: Cannot find module" mean in Node.js?

Error: Cannot find module (error code MODULE_NOT_FOUND) is thrown by the Node.js CommonJS module loader when require() cannot resolve the requested module name or file path. This error occurs both for missing npm packages and for incorrect relative file paths. Since Node.js 12, the error includes a requireStack array showing exactly which files triggered the failing require().

Why does "Cannot find module" happen even after npm install?

Several reasons the error can persist after running npm install:

  • You ran npm install in a different directory than where you run the script.
  • The package is in devDependencies and you ran npm install --production.
  • The install was corrupted — delete node_modules and package-lock.json and reinstall.
  • The package was installed globally with -g instead of locally.
  • A lockfile version mismatch caused the package to not resolve correctly.
How do I fix "Cannot find module" for an ESM-only package like chalk@5?

Packages like chalk@5, node-fetch@3, got@12, and ora@6 are ESM-only and cannot be loaded with require(). You have three options:

  • Use a dynamic import: const chalk = await import('chalk');
  • Downgrade to the last CJS version: npm install chalk@4
  • Convert your project to ESM: add "type": "module" to package.json and use import syntax throughout.
How do I fix "Cannot find module" for a directory import?

When you require('./models') and models is a directory, Node.js looks for models/index.js. If that file does not exist, you get MODULE_NOT_FOUND. Create an index.js inside the directory that exports the intended values:

// models/index.js
const User = require('./User');
const Post = require('./Post');
module.exports = { User, Post };
How do I fix "Cannot find module" in TypeScript projects?

In TypeScript projects, Cannot find module at runtime is usually caused by path aliases (e.g. @/utils) defined in tsconfig.json that are not resolved by Node.js at runtime. Fix it by registering tsconfig-paths:

node -r tsconfig-paths/register dist/app.js
# or with ts-node:
ts-node -r tsconfig-paths/register src/app.ts

Alternatively use a bundler (esbuild, webpack, Vite) that resolves aliases at build time.

How do I fix "Cannot find module" inside a Docker container?

In Docker, this error almost always means npm install did not run inside the container. Structure your Dockerfile to copy package.json first, then install, then copy source:

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "src/app.js"]

Also make sure node_modules is listed in your .dockerignore file.

How do I debug which paths Node.js is searching for a module?

Three useful techniques:

  • Print module.paths to see every node_modules directory searched, in order.
  • Use require.resolve('module-name') — returns the full resolved path on success, or throws a detailed error on failure.
  • Run NODE_DEBUG=module node app.js to trace every path Node.js attempts during resolution.
Works on macOS but fails on Linux — why?

macOS and Windows use case-insensitive filesystems by default, so require('./Utils') successfully loads utils.js. Linux uses a case-sensitive filesystem — the same require('./Utils') throws Cannot find module because there is no file named Utils.js. Fix: match the exact case of the filename in every require() or import statement. Linters like eslint-plugin-import can catch this automatically.

Related Errors