Home/Error Wiki/Vite import resolution
Vite / Rollup / Linux deployment

Rollup failed to resolve import

Fix the first unresolved specifier, not the final cascade. Classify it as a relative project file, root path, alias, bare dependency or dynamic import before installing or externalizing anything.

Evidence reviewed 2026-08-01. This page is ad-free while the error wiki is under quality review.

Start with the exact build error

[vite]: Rollup failed to resolve import "./components/Header" from "src/App.tsx"

Record the importer and specifier exactly. Run the production command locally from the same workspace root:

npm ci
npm run build

If the failure only appears on Vercel, Netlify or another Linux builder, filename case and omitted build-context files move to the top of the list.

Check the specifier against a local file inventory →

Classify the specifier

SpecifierResolution starts fromFirst check
./Header or ../lib/apiThe importing file’s directoryExact path, extension candidates and filename case.
/src/main.tsVite project rootCorrect root and file inclusion.
@/components/Headerresolve.aliasAlias exists in Vite and maps to an absolute filesystem path.
react or @scope/pkg/subpathPackage resolutionDependency is installed in this workspace and the subpath is exported.
import(`./pages/${name}.tsx`)Vite dynamic-import transformThe expression follows Vite’s supported variable limits or uses import.meta.glob.

1. Fix filename case for Linux

Vite’s troubleshooting guide explicitly calls out projects developed on case-insensitive Windows/macOS filesystems and built on case-sensitive Linux. Compare Git’s recorded path—not only Finder or Explorer—with the import:

git ls-files | sort
git status --short
git diff --cached --name-status

If the only change is case, make sure Git records it. A two-step rename is often clearer across filesystems:

git mv src/components/header.tsx src/components/header.tmp
git mv src/components/header.tmp src/components/Header.tsx

Then use exactly ./components/Header everywhere and run the build again.

2. Fix aliases in Vite, not only the editor

A TypeScript paths entry can make editor navigation work while the bundler still lacks an equivalent resolver rule. Vite documents that filesystem alias replacements should be absolute paths:

// vite.config.ts
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'

export default defineConfig({
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

Keep TypeScript, test runner and Vite aliases aligned. Do not add a plugin until you know which configuration source is intended to be authoritative.

3. Fix a missing dependency or blocked package subpath

For a bare specifier, inspect the correct workspace manifest and installed tree:

npm ls PACKAGE_NAME
npm explain PACKAGE_NAME
npm view PACKAGE_NAME exports

Install a package only if the import is intentional and the package is truly absent. Commit the manifest and lockfile. If the package exists but its exports field does not expose the requested subpath, import a documented public entry instead of reaching into internal files.

4. Confirm the file reached the build context

AI-generated changes and local-only files can work in a dev session but never reach CI. Check:

  • The file is tracked or deliberately generated before vite build.
  • .gitignore, Docker ignore rules, workspace filters and platform include rules do not omit it.
  • The deployment root points at the workspace containing the importer and dependency manifest.
  • Code generation runs before—not after—the production bundle.

5. Handle dynamic imports deliberately

Vite documents constraints for variable dynamic imports: the import must be statically analyzable, variables normally represent a filename only one level deep, and a file extension is required. For a broader known set, use a literal import.meta.glob pattern.

const pages = import.meta.glob('./pages/*.tsx')
const load = pages[`./pages/${name}.tsx`]

Validate that load exists before calling it. Do not construct arbitrary filesystem paths from user input.

Why “externalize it” is usually wrong for app source

Marking an unresolved application module as external suppresses bundling without creating the file in the browser. Externalization is appropriate only when the runtime truly provides that dependency and the deployment architecture documents it. It is not a generic fix for a misspelled component or missing npm package.

Verification gate

  • A clean npm ci followed by npm run build succeeds.
  • The test runs on Linux or the same container/platform image as production.
  • Git records the exact filename case.
  • No unresolved import warning was converted into a runtime 404.
  • The deployed workspace root and lockfile match local testing.

Primary sources