CalcSnippets Search
Vite 5 min read

How to Fix Vite Failed to Resolve Import Without Deleting node_modules on Repeat

A practical guide to fixing Vite failed to resolve import errors by checking the real import path, alias config, tsconfig paths, package exports, workspace links, and dependency optimization instead of reinstalling everything blindly.

Why this error keeps showing up: Vite is usually telling the truth. The import cannot be resolved from the file that asked for it, but the reason may be a typo, a missing alias, a package export boundary, or a workspace dependency that has not been built.

The error usually looks like this:

[plugin:vite:import-analysis] Failed to resolve import "@/components/Button"

or:

Failed to resolve import "some-package/subpath" from "src/App.tsx"

The tempting fix is to delete node_modules, reinstall, restart the dev server, and hope the machine feels more generous. Sometimes that works because the dependency cache was stale. Most of the time it just delays the real diagnosis.

Start with the exact import Vite is naming

Copy the failing import string and find where it appears:

rg '"@/components/Button"|some-package/subpath' src

Then check whether the target exists with the exact same spelling:

ls src/components

This sounds basic, but it catches a lot of failures:

  1. Button.tsx was renamed to button.tsx
  2. the import points at components/Button but the file lives in ui/Button
  3. the folder exists locally on macOS but fails in CI because Linux file paths are case-sensitive

If the import path is wrong, fix that before touching config.

If you use @/, configure Vite, not just TypeScript

TypeScript path aliases help the editor and type checker understand imports. Vite still needs its own resolver config at runtime and build time.

A common alias setup looks like this:

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

If your tsconfig.json has this:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

but vite.config.ts does not have the matching resolve.alias, the app can look fine in the editor and still fail in Vite.

Restart Vite after changing resolver config

Resolver config is loaded when the dev server starts. After changing vite.config.ts, restart the server:

npm run dev

If you are in a framework wrapper or a monorepo script, make sure the command you restarted is the one actually serving the failing app.

Check package subpaths and exports

This error also happens when the package exists but the subpath you imported is not public.

For example:

import thing from 'some-package/internal/thing';

may fail even when some-package is installed. Modern packages can define an exports field that controls which entry points are available to consumers. If a subpath is not exported, Vite may refuse to resolve it.

Check the package metadata:

node -p "require('./node_modules/some-package/package.json').exports"

Then import from a documented entry point instead of copying an internal path from a blog post, Stack Overflow answer, or compiled output.

Verify the dependency is installed where this app runs

In monorepos, the dependency may be installed at the root while the app package does not declare it. That can work accidentally in one setup and fail in another.

From the app directory, run:

npm ls some-package

or, with pnpm:

pnpm why some-package

If the app imports the package directly, the app package should usually declare the dependency directly. Do not rely on a sibling package or hoisting layout to make imports available.

Watch for workspace packages that need a build

If the import points to a local workspace package, Vite may be resolving source or built output depending on that package's package.json.

Check these fields:

{
  "main": "./dist/index.js",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts"
}

If the package points at dist but dist does not exist, Vite is not confused. The package has not been built.

Run the workspace build:

npm run build --workspace @acme/ui

or change the package to expose source intentionally during local development if that is how your repo is designed.

Use dependency optimization only for the right problem

Sometimes a dependency is present but Vite has trouble pre-bundling or detecting it. In that case, optimizeDeps.include can help:

// vite.config.ts
export default defineConfig({
  optimizeDeps: {
    include: ['some-package'],
  },
});

Use this after you have confirmed the package exists and the import path is valid. It should not be the first fix for a typo, a missing alias, or a package that does not export the path you are importing.

Clear Vite cache only after the config is correct

If the import path, alias, package export, and dependency declaration all look correct, then clear Vite's cached dependency metadata:

rm -rf node_modules/.vite
npm run dev -- --force

For pnpm or yarn projects, use the package manager command your repo already uses. The important part is that cache clearing comes after diagnosis, not before it.

A fast checklist

Use this order:

  1. confirm the file or package exists
  2. check exact case-sensitive spelling
  3. make Vite resolve.alias match TypeScript paths
  4. restart the Vite dev server
  5. check package exports before importing subpaths
  6. declare dependencies in the app that imports them
  7. build local workspace packages if their entry points target dist
  8. clear Vite cache only when the real configuration already makes sense

Bottom line

Failed to resolve import is not a reinstall problem by default. Treat it as a resolver question: where is this import coming from, what should it point to, and which tool knows that mapping? Once the path, alias, and package boundary agree, Vite usually stops complaining without a full dependency ritual.

Sources

Keep reading

Related guides