Three different problems share one message: a missing dependency, a relative path typo, or a case-sensitivity mismatch that works on macOS/Windows and fails on Linux. Match the fix to your case.
node_modules missing after clone, or the package is a devDependency used in production builds. npm ls <pkg> shows whether it's resolvable from your file.
require('config') looks in node_modules, not the local file — it must be require('./config'). The error's 'Require stack' points to the exact file that got it wrong.
require('./utils/Cool') vs utils/cool.js: macOS/Windows match case-insensitively; Linux in CI/production doesn't. Every 'works locally, breaks in CI' case-mismatch smells like this.
# full error output names the exact file+line; open it and verify the specifier
npm ls <pkg> ; npm install <pkg> # or: npm ci from a clean node_modules
grep -n "require(\"./\|require('./" <file> | head # every local import starts with ./ or ../ — match the exact filename case
require('fs') # NOT require('node:fs.js') or ./fs — bare built-in names, optionally node: prefix
ESM import behaves the same for paths but requires file extensions for local files (import './x.js'). pnpm/yarn strictness differences: a phantom dependency (undeclared but resolvable via hoisting) fails exactly like this when you switch package managers.
Case sensitivity: macOS/Windows resolve filenames case-insensitively, Linux doesn't. Compare the require specifier's case against the real filename character by character — ./utils/Help vs utils/help.js.
Check import context: a require from a file inside node_modules resolves differently; a package.json 'type' mismatch (ESM/CJS) changes rules; and NODE_PATH hacks break in strict ESM. Simplify to a plain dependency declared in package.json.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.