VibeRescue · Blog

Fix "Vercel build failed: Module not found" in AI-generated Next.js apps

October 15, 2026 · 8 min read

The app runs fine on your laptop. You push to GitHub, Vercel starts building, and a minute later you get:

Failed to compile.
./app/dashboard/page.tsx
Module not found: Can't resolve '@/components/ui/data-table'
> Build failed because of webpack errors
Error: Command "npm run build" exited with 1

It's one of the most-searched Next.js build errors, and code from AI tools runs into it all the time. Cursor, v0, Bolt and Claude write imports by following common conventions, which may not match how your project is actually laid out. The fix is usually one line. The trick is working out which of five causes you have. The build log already tells you most of it.

Read the log line properly

Open the failed deployment in Vercel, go to Build Logs, and find the first Module not found. It tells you two things:

Then reproduce it locally the same way Vercel builds: from a clean install.

rm -rf node_modules .next
npm ci          # or: pnpm install --frozen-lockfile
npm run build

If the clean local build passes but Vercel fails, the cause is almost always #1 or #2 below. If it fails locally too, you can fix it before pushing again.

1. File name casing (works on Mac, fails on Vercel)

macOS and Windows treat DataTable.tsx and data-table.tsx as the same file. Vercel builds on Linux, where they are two different files. AI agents often create a component as UserCard.tsx and import it as ./user-card, or rename a file in a way git never records.

# list what git actually has (that's what Vercel sees)
git ls-files | grep -i datatable

If git shows components/ui/DataTable.tsx but the import says data-table, fix one side to match. A case-only rename on Mac needs git mv, because otherwise git ignores it:

git mv components/ui/DataTable.tsx components/ui/data-table.tsx
git commit -m "fix: lowercase data-table filename"

2. The file was never committed

The agent created lib/utils.ts on your machine, but it's untracked, or .gitignore excludes it. It builds locally and doesn't exist on Vercel. Check:

git status --short          # ?? means untracked
git check-ignore -v lib/utils.ts   # prints the rule if it's ignored

Watch for .gitignore lines like lib/ (common in Python templates), /components, or *.local.ts. Projects uploaded to GitHub through the web uploader often lose folders or get flattened, so every file ends up at the repo root. If dozens of imports fail at once, compare the repo's tree with your local one before you touch any code.

3. The @/ alias doesn't point where the AI thinks

@/components/... is just an alias defined in tsconfig.json (or jsconfig.json). If the project has no src/ folder but the alias maps to ./src/*, every @/ import breaks. The reverse breaks too.

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

// project WITHOUT src/ (app/ and components/ at root)
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./*"] } } }

Also check for shadcn's components.json. It has its own aliases block, and a mismatch there makes npx shadcn add put components in the wrong folder. It's a classic way to get "it imports @/components/ui/button but the file is in src/components/ui/button.tsx".

A monorepo or a Vite project needs the alias in the bundler as well. Vite needs it in vite.config.ts, under resolve.alias, or through the vite-tsconfig-paths plugin.

4. The package isn't in package.json

If the specifier is a package name, the AI used a library it never installed, or installed it globally, or added it to the wrong package.json in a monorepo.

npm ls recharts            # "empty" means it's not a dependency
npm install recharts       # adds it to package.json AND the lockfile
git add package.json package-lock.json

Lockfiles cause their own variety of this error:

5. Server-only modules imported into client code

This one looks like: Module not found: Can't resolve 'fs', 'net', 'tls', 'dns' or 'child_process'. Nothing is actually missing. A Node.js-only library ended up in a bundle that runs in the browser. Usual causes:

// lib/db.ts: make accidental client imports fail loudly at build
import "server-only";
import { Pool } from "pg";
export const db = new Pool({ connectionString: process.env.DATABASE_URL });

Move the data access into a Server Component, a Route Handler (app/api/.../route.ts) or a Server Action, and have client components call it. Don't silence the error with webpack: { resolve: { fallback: { fs: false } } }. That only hides the problem, and you risk shipping server code, or secrets, to the browser.

Why AI tools keep causing this

A model writing an import is predicting what the path probably is. When your project differs from the most common layout (a src/ folder or not, PascalCase or kebab-case, shadcn in ui/ or not), it guesses wrong. Then, when the build fails, the usual AI "fix" is to create a second copy of the component at the guessed path, and now you have two drifting versions. A few habits stop this:

The 60-second triage

  1. Specifier starts with . or @/? Run git ls-files | grep -i <name>. If it's missing, see #2. If it's there with different casing, see #1. If it's there but under src/ versus root, see #3.
  2. Specifier is a package? Run npm ls <pkg>. If it's empty, see #4.
  3. Specifier is fs, net, tls or dns? See #5.

A worked example

Suppose Vercel fails with:

./src/app/settings/page.tsx
Module not found: Can't resolve '@/components/SettingsForm'

On your Mac, src/components/settings-form.tsx exists and the page imports it as @/components/SettingsForm. Locally it works because the filesystem is case-insensitive. On Vercel:

$ git ls-files | grep -i settings
src/components/settings-form.tsx

Git has the kebab-case name. Fix the import, not the file:

// before
import { SettingsForm } from "@/components/SettingsForm";
// after
import { SettingsForm } from "@/components/settings-form";

Or rename with git mv if you prefer PascalCase everywhere. Either way, one side has to match. Commit, push, and the next Vercel build should get past this line. If the next error is a different missing module, repeat the triage. It is normal for AI-generated apps to have several of these stacked; fixing them one at a time is faster than asking the agent to "fix the build" in one go.

Prevent it in CI

Add a GitHub Actions job that runs the same commands Vercel will. Failures then show up on the pull request, not after you merge:

# .github/workflows/build.yml
name: build
on: [pull_request, push]
jobs:
  next:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: "20", cache: npm }
      - run: npm ci
      - run: npm run build

Using npm ci (or pnpm install --frozen-lockfile) matters. It refuses to invent a lockfile, so a drift that would confuse Vercel fails in CI first. Pin Node to the same major version your host uses.

FAQ

Why does my Next.js app build locally but fail on Vercel with Module not found?

Most often the import casing does not match the file name. macOS and Windows ignore case, while Vercel builds on case-sensitive Linux. The second most common cause is a file that exists locally but was never committed to git.

How do I fix "Can't resolve '@/components/...'"?

Check that the paths alias in tsconfig.json points to the right folder: ./src/* if you have a src directory, ./* if you do not. Then confirm the file exists at that exact path with git ls-files.

Why does Next.js say Module not found: Can't resolve 'fs'?

A Node.js-only module was imported into code that runs in the browser, often through a "use client" component or a shared lib file. Move that code to a Server Component, Route Handler or Server Action, and add import "server-only" to the module.

Should I let the AI agent update my dependencies to fix build errors?

Review any change to package.json or the lockfile yourself. Agents sometimes bump frameworks to canary or new major versions, which causes new Module not found errors. Pin known-good versions and use npm ci in CI.

Not sure which of these it is?

Run the free Rescue Scan: paste a public GitHub repo and VibeRescue, an automated AI repair tool, classifies the problem (code bug, missing files, or missing secrets) before you pay anything. If it is something you can fix with this guide, we will tell you. If you want a fix run, it opens a pull request, with a full refund if the run can't fix it.

Run the free Rescue Scan →