Next.js Error: module_not_found — Module Not Found
./app/dashboard/page.tsx:3:0
Module not found: Can't resolve '@/components/UserCard'
1 | import { Suspense } from 'react';
> 2 | import { UserCard } from '@/components/UserCard';
| ^
3 |
4 | export default function Dashboard() {
https://nextjs.org/docs/messages/module-not-found
Module not found is a build-time error — webpack or Turbopack tried to walk your import graph, hit a path it couldn’t resolve, and stopped. Unlike runtime errors, it’s deterministic: the same code, the same filesystem, the same lockfile produces the same result every time. That makes it one of the easier Next.js errors to fix once you know which of the five buckets you’re in: missing install, wrong path, missing alias, blocked subpath, or ignored file.
The build output always tells you the import that failed and the file it came from. Read those two lines first; everything else is verifying which bucket applies.
Why this happens
- Package missing from node_modules. You imported a package that isn't installed, or your lockfile has it but `npm install` was never run on this checkout. Common after pulling a branch with new deps, switching package managers (npm ↔ pnpm), or building in a Docker stage that doesn't COPY node_modules and doesn't run install.
- Wrong relative path or filename case. `./components/userCard` vs `./components/UserCard.tsx`. macOS and Windows treat these as the same; Linux (and your Vercel/Docker build) does not. Builds that pass locally and fail in CI are almost always case-sensitivity bugs.
- Path alias declared in tsconfig but not in the bundler config. TypeScript's `paths` (`@/*: ./src/*`) only affects type-checking. Next.js 13+ reads it automatically, but custom webpack configs, Jest, and older Next versions need the alias mirrored in `next.config.js` `webpack.resolve.alias` or in the test runner's moduleNameMapper.
- Module exists but uses a non-existent subpath export. Modern packages declare `exports` in their `package.json`. Importing `lodash/fp/curry` from a package that doesn't expose that subpath fails even though the file exists on disk. The error is identical: 'can't resolve …'.
- File ignored by `.dockerignore`, `.vercelignore`, or `.gitignore`. The file exists locally but never reaches the build environment. Common with `.env`-style files in `.dockerignore`, or a `dist/` folder that's gitignored but imported from.
How to fix it
Fixes are ordered by likelihood. Start with the first one that matches your context.
1. Reinstall dependencies and clear the build cache
Most module-not-found errors after a branch switch or package.json change are stale node_modules or a stale `.next` cache. Nuke and reinstall in the right order.
# Stop dev server first.
rm -rf node_modules .next
rm -f package-lock.json yarn.lock pnpm-lock.yaml # only if mismatched
npm install # or pnpm install / yarn
# If it's a Next.js cache issue specifically:
npx next build --no-lint
2. Verify the import path's case matches the file on disk
Linux file systems are case-sensitive. If your import says `./UserCard` and the file is `userCard.tsx`, it works on macOS and Windows but fails on Vercel and Docker. Use `git ls-files` to see the actual case Git tracks.
# See the real, tracked filename:
git ls-files | grep -i usercard
# Rename a file's case in Git (single-step, cross-platform-safe):
git mv components/userCard.tsx components/UserCard.tsx
git commit -m "fix: rename UserCard to match imports"
3. Mirror tsconfig path aliases everywhere they're consumed
Next.js 13+ reads `tsconfig.json` `paths` automatically for the main build. Your test runner and any custom webpack config don't. Declare the alias in every config that resolves modules.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"]
}
}
}
4. Check the package's exports field for valid subpaths
Open `node_modules/<pkg>/package.json` and look at `exports`. If the path you're importing isn't listed, you're importing a subpath the package's author didn't expose. Either import from the documented entry point or use the package's deep-import escape hatch (rarely advisable).
// BAD — react-icons subpath not exported in some versions
import { FaUser } from 'react-icons/fa/FaUser';
// GOOD — use the documented entry
import { FaUser } from 'react-icons/fa';
5. Audit your ignore files
Run `git check-ignore -v <path>` to see if a file is ignored. For Vercel: `.vercelignore` is undocumented but real — make sure your `src/` is not in it. For Docker: print the build context size; if it's much smaller than your repo, `.dockerignore` is dropping files you need.
Detection and monitoring in production
Wire `next build` into CI on every PR — module-not-found errors are deterministic and always catchable in CI before they hit production. Add a `tsc --noEmit` step alongside; TypeScript catches missing-module errors faster than a full build. For monorepos, run a fresh checkout build (no cache) weekly to catch case-sensitivity bugs before someone's Linux-only deploy fails.
Related errors
- nextjshydration_failedThe HTML React rendered on the server doesn't match what React tries to render on the client during hydration. The two trees disagree about a node, so React throws and falls back to a full client re-render.
- nextjsFUNCTION_INVOCATION_TIMEOUTA Vercel serverless function (a Next.js API route, server action, or `getServerSideProps`) didn't return a response within the plan's max execution time — 10s on Hobby, 60s on Pro, 900s on Enterprise. Vercel kills the invocation and returns 504.
- nodejsERR_REQUIRE_ESMYour CommonJS file used `require('some-package')` but the package is now ESM-only (its `package.json` has `"type": "module"` or `"exports"` only points to `.mjs`). Node's CJS loader can't synchronously load an ESM module.
- pythonModuleNotFoundErrorThe Python interpreter walked `sys.path` and couldn't find the module you imported. Most common cause: you installed the package in a different environment (different venv, different Python version, system pip vs project pip) than the one running your code.
- postgresECONNREFUSEDYour application tried to open a TCP connection to Postgres and the OS rejected it — Postgres isn't listening on the host:port you specified, or a firewall blocked the connection.
Frequently asked questions
Why does the build pass locally on my Mac but fail on Vercel with module not found? +
I installed the package but I still get module not found. +
How is `Module not found` different from `Cannot find module` in Node.js? +
Should I commit node_modules to fix this? +
My TypeScript path alias works in the editor but fails at build time. +
Why does `import 'foo/internal/bar'` fail with a recent version of `foo`? +
I'm using a monorepo with workspaces and getting module not found from another package. +
Can a circular dependency cause module not found? +
When to escalate to Next.js support
Module-not-found is a configuration or filesystem issue 99% of the time, not a Next.js bug. Before filing upstream: confirm the same import works in a brand-new `create-next-app` with the same Next.js version. If it doesn't, file at github.com/vercel/next.js with the failing repo. If it does work in a fresh app, the difference is in your config (next.config.js, tsconfig, or package.json) — diff against a known-good repo to isolate.