# Why Is My Vite Alias Not Working? Fixing Path Resolution for the src Folder

> Fix your Vite alias not working with source folder imports. Learn common causes like relative paths, missing slashes, or dependency conflicts and how to resolve them quickly.

- Repository: [Vite/vite](https://github.com/vitejs/vite)
- Tags: how-to-guide
- Published: 2026-02-18

---

**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`](https://github.com/vitejs/vite/blob/main/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`](https://github.com/vitejs/vite/blob/main/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`](https://github.com/vitejs/vite/blob/main/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`](https://github.com/vitejs/vite/blob/main/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`](https://github.com/vitejs/vite/blob/main//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`](https://github.com/vitejs/vite/blob/main/./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:

1. **Config parsing** – [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts) is loaded, `resolve.alias` entries are stored in the final resolved config.
2. **Pre‑alias plugin** – The `preAliasPlugin` builds a pattern list from `resolve.alias` via `getAliasPatterns` in [`packages/vite/src/node/plugins/preAlias.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/preAlias.ts).
3. **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 alias `replacement`.
4. **Optimization pass** – If the import is a bare specifier (matched by `bareImportRE` in [`packages/vite/src/node/utils.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts)) and the dev server is optimizing deps, the alias may be short‑circuited by the optimizer.
5. **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:

```typescript
// 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`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/utils.ts).

### Syncing with TypeScript Path Mapping

If you use TypeScript, ensure Vite reads your [`tsconfig.json`](https://github.com/vitejs/vite/blob/main/tsconfig.json) to avoid a **vite alias not working** mismatch:

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

```

```typescript
// 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:

```typescript
// 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`](https://github.com/vitejs/vite/blob/main/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`](https://github.com/vitejs/vite/blob/main/docs/config/shared-options.md) (section *resolve.alias*) | Official documentation of the alias option, including the requirement for absolute paths. |
| [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts) (project‑level) | Where developers declare their own alias mapping; the file that drives the whole alias mechanism. |
| [`tsconfig.json`](https://github.com/vitejs/vite/blob/main/tsconfig.json) (optional) | Provides TypeScript path mapping; can be synchronized with Vite via `resolve.tsconfigPaths`. |
| [`packages/vite/src/node/utils.ts`](https://github.com/vitejs/vite/blob/main/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 `preAliasPlugin` in [`packages/vite/src/node/plugins/preAlias.ts`](https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/preAlias.ts) before 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 so `withTrailingSlash` matching works correctly for nested imports like `@/components/Foo.vue`.
- **TypeScript requires explicit sync** – Enable `resolve.tsconfigPaths: true` or duplicate mappings in `resolve.alias` to 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`](https://github.com/vitejs/vite/blob/main/tsconfig.json) paths unless you set `resolve.tsconfigPaths: true`. For the build to succeed, Vite only needs the alias in [`vite.config.ts`](https://github.com/vitejs/vite/blob/main/vite.config.ts), but duplicating it in [`tsconfig.json`](https://github.com/vitejs/vite/blob/main/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`.