'Module not found: Can't resolve' — fix the import
Quick answer: webpack could not resolve a module you imported, at build time. The usual causes are a wrong or case-mismatched relative path, a dependency you forgot to install (or that is only in devDependencies), or importing a Node-only module like fs or path into browser code. Fix the path, install the package in the right place, and keep server-only modules out of client code.
What the error looks like
It names what it could not resolve and the directory it searched:
Module not found: Error: Can't resolve './components/Button' in '/app/src'
# a package that is not installed:
Module not found: Error: Can't resolve 'lodash' in '/app/src'
# a Node built-in in browser code:
Module not found: Can't resolve 'fs'
A path starting with ./ or ../ is a file-path problem; a bare name like lodash is a missing package; a Node built-in like fs means server-only code leaked into the browser bundle.
Why it happens
Wrong path or case mismatch
./Button vs ./button - fine on macOS, broken on Linux/CI, which is case-sensitive.
Dependency not installed
Forgot npm install, or the package is only in devDependencies and CI installs prod-only.
Node built-in in browser code
Importing fs, path, or crypto into client-bundled code, where they do not exist.
Path alias not configured
@/components works only if both webpack resolve.alias and tsconfig paths define it.
Diagnose it in three steps
Read the name and the search directory
# "Can't resolve 'X' in 'DIR'" - is X a package (bare name) or a path (./ or ../)?If it is a package, is it installed?
npm ls lodash
# missing? install it - and check which section of package.json it lands in.If it is a path, check it exactly (case included)
git ls-files src/components | grep -i button
# does the file exist, with that exact name and case?Correct the path, install the dep, keep server code server-side
Match the import to the file exactly (including case), install missing packages into dependencies if they run at build/runtime, and never import Node built-ins into browser code.
# install a missing package into the right section
npm install lodash # runtime dep -> "dependencies"
// fix case to match the file exactly (Linux is case-sensitive)
import Button from './components/Button'; // file: components/Button.tsx
// configure an alias in BOTH places
// webpack: resolve: { alias: { '@': path.resolve(__dirname, 'src') } }
// tsconfig: "paths": { "@/*": ["src/*"] }
For a Node built-in error in the browser, move that code to the server (an API route, a server component, or a backend service) rather than polyfilling it into the client bundle.
Catch the bad build before it ships
A case mismatch or a devDependency-in-prod that only breaks in CI is a reproducibility gap between your machine and the build environment. On your own servers, Infraveil runs deploys from a pinned, Linux-consistent build and catches a failed build before it serves traffic - so the import error surfaces in the pipeline, not in production, with recovery approval-gated and recorded.
Frequently asked questions
What does 'Module not found: Can't resolve' mean?
Webpack could not resolve an import to a file or package at build time - the path is wrong, the package is not installed, or the target is something it cannot bundle, like a Node built-in in browser code.
Why does it build locally but fail in CI?
Usually case-sensitivity (Linux/CI is case-sensitive, macOS/Windows are not) or a dependency only in devDependencies that CI does not install. Match the case exactly and put runtime imports in dependencies.
Why can't it resolve 'fs' or 'path'?
Those are Node built-ins imported into browser-bundled code, where they do not exist. Move that logic to the server. In Next.js it usually means a server-only module was imported into a client component.
How do I set up path aliases like @/components?
Define the alias in both the bundler (webpack resolve.alias or the framework equivalent) and tsconfig.json paths, so the bundler and the type checker agree. A mismatch is a common cause of can't-resolve on aliased imports.
Client-side, no signup — they run in your browser.