Deploy Error Decoder

'Cannot find module' after deploy — how to fix MODULE_NOT_FOUND

Quick answer: Error: Cannot find module (MODULE_NOT_FOUND) means Node couldn't resolve a require/import. After a deploy it's almost always one of: dependencies weren't installed (no node_modules), a devDependency is needed at runtime, a path's casing differs on case-sensitive Linux, or a build step didn't run. Check which module is missing, whether it's in package.json, and run npm ci.

What the error looks like

Node prints the module it tried and failed to resolve:

Error: Cannot find module 'express'
Require stack:
- /app/dist/server.js
    at Function._resolveFilename (node:internal/modules/cjs/loader:1145:15)
  code: 'MODULE_NOT_FOUND'

Two flavors: a package name ('express') means a dependency isn't installed; a relative path ('./utils/log') means a file is missing, mis-cased, or wasn't built. "Works locally, fails in prod" is the classic signature.

Why it appears only after deploy

Dependencies weren't installed

No node_modules on the server, or npm ci didn't run before start. Locally you already have them.

A devDependency is needed at runtime

Prod installs skip devDependencies. If your app requires one at runtime, it's missing in production.

Case-sensitive paths on Linux

./Utils resolves on macOS/Windows but not on Linux. The import casing must match the filename exactly.

The build didn't run

A TypeScript/bundler step was skipped, so dist/ is missing or stale and the imported file isn't there.

Diagnose it in three steps

1

Read which module is missing

Package name or relative path? That single distinction tells you which branch you're on.

# Is it a declared dependency?
node -e "console.log(require('./package.json').dependencies)"
cat package.json | grep -A20 '"dependencies"'
2

Reinstall cleanly from the lockfile

# Reproducible install — matches the lockfile exactly
rm -rf node_modules
npm ci          # not "npm install"
ls node_modules/express   # confirm it's actually there
3

For a relative path, check casing and the build

# Linux is case-sensitive — these are different files:
import { log } from './utils/Log';   // file is utils/log.ts ? -> fails on Linux
# And make sure the build actually produced the file:
npm run build && ls dist/
The real fix

Make the package the deploy ships be the package that runs

MODULE_NOT_FOUND in production is almost always a gap between what you built and what you shipped. Close it:

  • Use npm ci in the pipeline, not npm install — it installs exactly the lockfile, every time.
  • Move runtime deps out of devDependencies — if the running app needs it, it's a dependency.
  • Build before you ship, and ship the build output — verify dist/ exists in the artifact, not just on your laptop.
  • Match import casing to filenames — and consider an eslint rule so case drift fails CI on macOS too.
How Infraveil handles this

Verified packages — caught at the gate, not in production

Infraveil is a backend operations control plane that runs on your own servers. Nothing runs until it's verified: the agent checks the package it's handed before it starts the service, so a missing dependency or a broken build is caught at the deploy gate rather than crashing in production. Every release is approval-gated and recorded, with one-click rollback to the last package that actually started.

Deploys are verified before they run — a broken package never reaches users
One-click rollback to the last known-good build
Every deploy recorded in a tamper-evident trail, on servers you control

Frequently asked questions

What does 'Cannot find module' mean?

Node tried to resolve a require/import and couldn't find it. The MODULE_NOT_FOUND code accompanies it. The missing item is either an uninstalled package or a missing/mis-pathed file.

Why does it work locally but not in production?

Locally you have all dependencies and the right build output. Production may have skipped devDependencies, not run npm ci, not run the build, or be case-sensitive (Linux) where your machine isn't.

Should I use npm install or npm ci on deploy?

Use npm ci. It installs exactly what the lockfile specifies, fails if package.json and the lockfile disagree, and is reproducible — ideal for CI/CD and production.

Why does the same import fail only on Linux?

Linux filesystems are case-sensitive. ./Utils/Log and ./utils/log are different paths there, even though macOS and Windows treat them as the same. Match the import casing to the real filename.