Vite: Fix "Failed to resolve import" (path aliases)
  You’ve just set up path aliases in your Vite project, replacing those unwieldy ../../../components imports with clean @/components paths. But now Vite throws a frustrating error: “Failed to resolve import”. This happens because Vite and TypeScript handle module resolution differently, and fixing it requires syncing two separate configurations.
This guide shows you exactly how to fix Vite path aliases errors using two proven methods: manual configuration for full control, or the automated vite-tsconfig-paths plugin for simplicity.
Key Takeaways
- Vite and TypeScript require separate path alias configurations that must align
 - Manual configuration offers full control but requires maintaining two config files
 - The vite-tsconfig-paths plugin automates synchronization between configs
 - Common issues include missing @types/node, syntax mismatches, and ESM conflicts
 
The “Failed to resolve import” Error in Vite
The Vite Failed to resolve import error appears when your bundler can’t locate modules using your custom path aliases. You’ll see variations like:
[vite] Internal server error: Failed to resolve import "@/components/Header"Cannot find module '@/utils' or its corresponding type declarations- TypeScript error 
TS2307in your IDE 
These errors block your development server, break hot module replacement, and prevent successful builds—turning what should be a productivity boost into a roadblock.
Understanding Why Vite Path Aliases Fail
The Two-Config Problem
Vite uses Rollup for bundling, while TypeScript handles type checking separately. Each tool needs its own configuration:
- Vite needs 
resolve.aliasinvite.config.tsfor module bundling - TypeScript needs 
pathsintsconfig.jsonfor type checking and IDE support 
When these configurations don’t match, you get import resolution errors. Vite might understand @/components, but TypeScript doesn’t—or vice versa.
Common Triggers for Import Errors
Three issues cause most Vite resolve alias errors:
- Missing Node.js types: Using 
path.resolve()without@types/node - Syntax mismatches: Vite uses object notation while TypeScript uses array patterns
 - Module format conflicts: Using CommonJS-specific variables like 
__dirnamein ESM projects 
Method 1: Manual Configuration for Vite TypeScript Aliases
Step 1: Configure vite.config.ts
First, install the required Node.js types:
npm install -D @types/node
Then update your Vite configuration:
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url)),
      '@components': fileURLToPath(new URL('./src/components', import.meta.url)),
      '@utils': fileURLToPath(new URL('./src/utils', import.meta.url))
    }
  }
})
For CommonJS projects, you can use path.resolve() with __dirname:
// vite.config.ts (CommonJS)
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
      '@components': path.resolve(__dirname, './src/components'),
      '@utils': path.resolve(__dirname, './src/utils')
    }
  }
})
Step 2: Update tsconfig.json
Configure TypeScript to recognize the same aliases:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"],
      "@components/*": ["src/components/*"],
      "@utils/*": ["src/utils/*"]
    }
  }
}
Note the syntax difference: Vite uses '@components' while TypeScript uses "@components/*" with array values.
Verifying Your Setup
Test your configuration with an import:
// Before: import Button from '../../../components/Button'
import Button from '@components/Button'
Your IDE should provide autocomplete suggestions, and npm run dev should start without errors.
Discover how at OpenReplay.com.
Method 2: Automated Setup with vite-tsconfig-paths
Installation and Basic Setup
The vite-tsconfig-paths plugin automatically syncs your TypeScript paths with Vite:
npm install -D vite-tsconfig-paths
Update your Vite config:
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
  plugins: [react(), tsconfigPaths()]
})
That’s it. The plugin reads your tsconfig.json paths and configures Vite automatically.
Benefits Over Manual Configuration
- Single source of truth: Update only 
tsconfig.json - No synchronization errors: Aliases always match
 - Cleaner config files: Less boilerplate code
 - Monorepo support: Handles complex workspace setups
 
Troubleshooting Vite Resolve Alias Errors
JavaScript Projects Without TypeScript
For JavaScript projects, create a jsconfig.json instead:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}
The vite-tsconfig-paths plugin works with jsconfig.json too.
Monorepo and Advanced Scenarios
In monorepos, ensure your paths are relative to the workspace root:
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@app/*": ["packages/app/src/*"],
      "@shared/*": ["packages/shared/src/*"]
    }
  }
}
For Windows users, always use forward slashes (/) in path configurations—both Vite and TypeScript normalize them correctly.
Build vs Development Discrepancies
If aliases work in development but fail during build:
- Check for case sensitivity issues (especially on Linux/macOS)
 - Ensure 
baseUrlis set correctly - Verify all aliased paths exist in your build output
 - Check that your build tool preserves the alias configuration
 
Quick Reference: Manual vs vite-tsconfig-paths
| Aspect | Manual Configuration | vite-tsconfig-paths | 
|---|---|---|
| Setup complexity | Two files to maintain | One file only | 
| Control | Full customization | Follows tsconfig.json | 
| Maintenance | Manual synchronization | Automatic | 
| Best for | Simple projects, specific requirements | Most projects, monorepos | 
| Performance | Slightly faster (no plugin overhead) | Negligible difference | 
Conclusion
Fixing Vite Failed to resolve import errors comes down to aligning module resolution between Vite and TypeScript. The manual method gives you precise control over both configurations, while vite-tsconfig-paths eliminates synchronization headaches entirely.
For most projects, start with vite-tsconfig-paths—it’s simpler and prevents configuration drift. Switch to manual configuration only when you need different aliasing strategies between development and production, or when working with unusual build setups that require custom resolution logic.
FAQs
Vite and TypeScript use separate configuration systems. TypeScript reads tsconfig.json for type checking while Vite uses vite.config.ts for bundling. Both need matching path alias configurations to work correctly.
Yes, create a jsconfig.json file with your path mappings and configure Vite aliases manually or use vite-tsconfig-paths which supports both jsconfig.json and tsconfig.json files.
Modern Vite projects use ES modules where __dirname isn't available. Use import.meta.url with fileURLToPath for ESM compatibility, or __dirname only in CommonJS environments.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.