Next.js build fails only in CI/deploy with `Module not found: Can't resolve '@/lib/storage'` even though the file exists and `next build` succeeds locally. The module was never committed: `.gitignore` contained an unanchored pattern (`storage`) intended for a root-level upload directory, and because a pattern with no `/` matches at any depth, it also matched the source directory `lib/storage/`. Local builds worked because the file was present on disk but untracked, so the breakage only appeared once a build ran from a fresh clone.
Fix: Anchor .gitignore patterns that are meant to match only a top-level directory by prefixing them with `/` (`storage` -> `/storage`), then commit the wrongly-ignored source. Diagnose the class of bug with `git status --ignored --short app lib src` (lists ignored paths inside source trees) or `git check-ignore -v <path>` (prints the exact .gitignore line responsible). A useful general rule: any "module not found for a file that plainly exists" that reproduces only on CI or a fresh clone is an untracked-file problem, not a resolver/alias problem — verify with `git ls-files <dir>` before touching tsconfig/jsconfig paths or bundler aliases. Anchoring is the correct fix rather than a negation pattern (`!lib/storage/`), because git will not re-include a file if a parent directory is itself excluded.
gitignorecimodule-not-foundnext.jsturbopackgit
References
- https://git-scm.com/docs/gitignore — The gitignore pattern format specifies that if a pattern does not contain a slash, git treats it as a shell glob matched against the pathname relative to the .gitignore location at any level below it; a leading slash anchors the pattern to the containing directory. This is why `storage` matches `lib/storage/` while `/storage` does not. The same page documents that it is not possible to re-include a file if a parent directory of that file is excluded.
- https://git-scm.com/docs/git-check-ignore — git check-ignore -v prints the source .gitignore file, line number, and pattern that causes a given path to be excluded, which identifies the offending pattern directly.
- https://nextjs.org/docs/messages/module-not-found — Next.js documents the module-not-found error as the module simply not being resolvable at the given path, confirming that a bundler/alias-level fix is inappropriate when the file is absent from the build context.