Vite’s alias feature is surprisingly powerful for managing complex import structures, allowing you to treat abstract paths like @/components/Button as concrete filesystem locations.

Let’s see it in action. Imagine a simple Vue project.

<template>
  <div>
    <MyButton>Click Me</MyButton>
  </div>
</template>

<script setup>
import MyButton from '@/components/MyButton.vue';
</script>

Here, @/components/MyButton.vue looks like a relative path, but it’s not. It’s an alias.

In your vite.config.js, you define these aliases.

// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';

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

The resolve.alias option is where the magic happens. Vite uses enhanced-resolve under the hood, the same resolver used by Webpack, so the configuration is quite familiar. The keys in the alias object are the strings you’ll use in your imports (e.g., '@'), and the values are the absolute or relative paths they should resolve to. path.resolve(__dirname, './src') tells Node.js to construct an absolute path to the src directory relative to the current file (vite.config.js). So, @/components/MyButton.vue effectively becomes /path/to/your/project/src/components/MyButton.vue during the build process.

This solves a few problems. First, it keeps your imports clean and readable, especially in large projects where deeply nested relative paths like ../../../utils/helpers become a maintenance nightmare. Second, it decouples your code from its physical location on the filesystem. If you decide to reorganize your src directory, you only need to update your Vite configuration, not every single import statement in your codebase. Third, it enables a more modular project structure. You can define aliases for common directories like ~/ to point to node_modules, allowing you to import directly from installed packages without needing to remember their exact location within node_modules.

The resolve.extensions option in Vite is also crucial here. It specifies the file extensions Vite should try to resolve when an import doesn’t explicitly include one.

// vite.config.js (continued)
export default defineConfig({
  // ... other config
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
    extensions: ['.vue', '.js', '.jsx', '.ts', '.tsx', '.json', '.wasm'],
  },
});

When you import MyButton from @/components/MyButton, Vite first looks for MyButton.vue because .vue is in resolve.extensions. If it finds it, it uses that file. If not, it tries MyButton.js, and so on. This means you can write import MyButton from '@/components/MyButton' and Vite will correctly find MyButton.vue if it exists.

When you use a trailing slash in an alias, like '@/': path.resolve(__dirname, './src/'), it behaves slightly differently. If you import import utils from '@/utils', Vite will look for a directory named utils inside your src directory and then try to resolve index.js (or other extensions) within that directory. This is a common pattern for aliasing directories that contain an index file, allowing you to import them as if they were modules themselves.

The resolve.modules option, while less commonly overridden than alias, can also affect resolution. By default, it includes ['node_modules'], meaning Vite will look for modules in the node_modules directory. If you were to add a custom directory to resolve.modules, like ['node_modules', path.resolve(__dirname, './src/shared')], Vite would also search your src/shared directory when it can’t find a module in node_modules. This can be useful for managing shared libraries or components that aren’t installed via npm.

The most surprising thing about Vite’s alias system is how seamlessly it integrates with its HMR (Hot Module Replacement) capabilities. When you change a file that’s part of an alias, Vite’s HMR doesn’t just update the specific file; it intelligently invalidates the module graph based on the resolved alias path. This means your alias changes are reflected instantly in the browser without a full page reload, even if the original import path was abstract.

The next concept you’ll likely encounter is managing environment variables within your Vite-powered application.

Want structured learning?

Take the full Vite course →