Why Is My Vite Alias Not Working? Fixing Path Resolution for the src Folder
Vite aliases fail most often because the alias value is a relative path, lacks a trailing slash, or conflicts with dependency optimization, all of which are handled by the preAlias plugin before standard resolution occurs.
When your vite alias is not working for the src folder, the issue usually stems from how Vite's internal resolver processes the resolve.alias configuration. The core logic lives in packages/vite/src/node/plugins/preAlias.ts, where the getAliasPatterns function builds matchers that rewrite import strings before the dependency optimizer or file system resolver sees them.
Common Reasons Your Vite Alias Is Not Working
| Reason | What happens under the hood | Fix |
|---|---|---|
| Alias value is a relative path | The alias matcher treats the replacement as‑is; relative values are not turned into absolute file‑system paths, so the resolver cannot locate the target file. | Use an absolute path (e.g. path.resolve(__dirname, 'src')) or rely on tsconfig.json path mapping. |
| Missing trailing slash | Vite matches import strings against the find pattern with withTrailingSlash. If the alias points to src without a trailing slash, imports like import Foo from '@/components/Foo.vue' may not match because Vite expects src/ as the base. |
Append a slash to the alias target (src/) or use a glob‑style pattern (/@/ → src/). |
| Alias collides with optimized deps | During dev, Vite pre‑bundles dependencies. If a module is both aliased and optimized, the preAliasPlugin tries to resolve it through the optimizer first. If the optimizer resolves the original id before the alias replacement, the alias is effectively bypassed. |
Ensure the aliased path is outside node_modules or add it to optimizeDeps.include / exclude as appropriate, or disable optimization for that import. |
| TS/JS path mapping mismatch | Vite’s alias resolver does not read tsconfig.json unless resolve.tsconfigPaths is true. If you rely only on TypeScript’s paths option, Vite will still try to resolve the raw import, resulting in “module not found”. |
Enable resolve.tsconfigPaths: true or duplicate the mapping in resolve.alias. |
| Server not restarted | Alias changes are read when the dev server starts. Updating vite.config.ts without restarting leaves the old resolver in place. |
Restart vite (npm run dev or yarn dev) after changing alias definitions. |
| Incorrect import syntax | Importing with a leading slash (/components/Foo.vue) tells Vite to resolve from the project root (root option) rather than the alias. |
Use the alias prefix (@/components/Foo.vue) or a relative path (./components/Foo.vue). |
How Vite Resolves Aliases
Understanding the resolution pipeline explains why a vite alias is not working even when the configuration looks correct:
- Config parsing –
vite.config.tsis loaded,resolve.aliasentries are stored in the final resolved config. - Pre‑alias plugin – The
preAliasPluginbuilds a pattern list fromresolve.aliasviagetAliasPatternsinpackages/vite/src/node/plugins/preAlias.ts. - Import resolution – For each import, Vite checks the alias patterns first (via
matches). If a match is found, the import id is replaced with the aliasreplacement. - Optimization pass – If the import is a bare specifier (matched by
bareImportREinpackages/vite/src/node/utils.ts) and the dev server is optimizing deps, the alias may be short‑circuited by the optimizer. - Final module loading – After alias resolution (or after the optimizer returns a resolved id), the normal resolver loads the file from the file system.
Fixing the Vite Alias to the src Folder
Using Absolute Paths with Trailing Slashes
The most reliable fix when your vite alias is not working is to ensure the replacement is absolute and ends with a slash:
// vite.config.ts
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
resolve: {
alias: {
// absolute path + trailing slash – works for any import style
'@': path.resolve(__dirname, 'src') + '/',
},
},
})
Why it works – path.resolve guarantees an absolute path, and the + '/' ensures the matcher includes the trailing slash required by Vite’s internal withTrailingSlash logic in packages/vite/src/node/utils.ts.
Syncing with TypeScript Path Mapping
If you use TypeScript, ensure Vite reads your tsconfig.json to avoid a vite alias not working mismatch:
// tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
// vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
resolve: {
// Enable tsconfig‑based alias resolution
tsconfigPaths: true,
},
})
Now both the TypeScript compiler and Vite share the same @/ mapping.
Handling Dependency Optimization Conflicts
When an aliased package collides with pre‑bundling, explicitly exclude it:
// vite.config.ts
import { defineConfig } from 'vite'
import path from 'node:path'
export default defineConfig({
resolve: {
alias: {
'@my-lib': path.resolve(__dirname, 'src/my-lib/') // local source version
},
},
optimizeDeps: {
// Prevent Vite from treating the aliased package as an external dep
exclude: ['my-lib'],
},
})
Key Files in Vite's Alias Resolution
| File | Why it matters |
|---|---|
packages/vite/src/node/plugins/preAlias.ts |
Core plugin that builds alias matchers via getAliasPatterns and integrates them with the dev‑dependency optimizer. |
docs/config/shared-options.md (section resolve.alias) |
Official documentation of the alias option, including the requirement for absolute paths. |
vite.config.ts (project‑level) |
Where developers declare their own alias mapping; the file that drives the whole alias mechanism. |
tsconfig.json (optional) |
Provides TypeScript path mapping; can be synchronized with Vite via resolve.tsconfigPaths. |
packages/vite/src/node/utils.ts (helpers bareImportRE, withTrailingSlash) |
Helper utilities used by the pre‑alias plugin to match and rewrite import strings. |
Summary
- Vite aliases are processed first by the
preAliasPlugininpackages/vite/src/node/plugins/preAlias.tsbefore standard resolution or dependency optimization. - Relative paths fail – Always use
path.resolve(__dirname, 'src')to ensure absolute file system paths. - Trailing slashes matter – Append
/to the alias target sowithTrailingSlashmatching works correctly for nested imports like@/components/Foo.vue. - TypeScript requires explicit sync – Enable
resolve.tsconfigPaths: trueor duplicate mappings inresolve.aliasto prevent "module not found" errors. - Restart the server – Alias changes only take effect after restarting the Vite dev server.
Frequently Asked Questions
Why does my Vite alias work for some imports but not others?
This usually happens when the alias target lacks a trailing slash or when some imports match the bareImportRE pattern and get intercepted by the dependency optimizer first. Check that your alias ends with / and that the failing import is not being pre‑bundled from node_modules before the alias can rewrite it.
Do I need to configure aliases in both vite.config.ts and tsconfig.json?
Only if you want TypeScript to recognize the aliases during type checking. Vite does not automatically read tsconfig.json paths unless you set resolve.tsconfigPaths: true. For the build to succeed, Vite only needs the alias in vite.config.ts, but duplicating it in tsconfig.json ensures your IDE and tsc agree with Vite's resolver.
Why do I need to restart the dev server after changing an alias?
Vite reads resolve.alias during server initialization to build the pattern matchers in getAliasPatterns. These patterns are cached in the preAliasPlugin instance for performance. Changing the config file on disk does not trigger a rebuild of these internal matchers, so the old alias rules remain active until you restart the process.
Can I use a relative path like './src' in resolve.alias?
Technically you can, but it will cause resolution failures. The alias replacement is applied as‑is to the import string. If the replacement is relative, Vite's resolver interprets it relative to the importing file's location rather than the project root, leading to "module not found" errors. Always use absolute paths via path.resolve.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →