Vite’s killer feature isn’t its speed, it’s that it makes you forget you’re using a build tool at all.

Let’s get a Vite project up and running. The simplest way is with create-vite, the official scaffolding tool. Open your terminal, navigate to where you want your project, and run:

npm create vite@latest my-vite-app --template react

This command does a few things. npm create vite@latest tells npm to fetch the latest version of the create-vite package and execute it. my-vite-app is the name of the directory that will be created for your project. --template react specifies that we want a React project. You could also use vue, preact, lit, svelte, or vanilla (for plain JavaScript).

After running that, you’ll see some output prompting you to navigate into your new directory and install dependencies.

cd my-vite-app
npm install

npm install reads the package.json file in your new my-vite-app directory and downloads all the necessary packages. You’ll notice a node_modules folder appears, containing all these dependencies. Vite itself, along with any framework-specific plugins (like @vitejs/plugin-react), will be installed here.

Now, to see your project in action, run:

npm run dev

This command executes the dev script defined in your package.json. For Vite, this script starts the development server. You’ll see output like this:

  VITE v5.2.10  ready in 650 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Open your browser to http://localhost:5173/. You should see the default Vite starter page for your chosen framework. The magic here is that Vite is not bundling your code during development. It’s serving your files directly to the browser using native ES modules. When you import a file (e.g., import React from 'react'), the browser fetches that module. Vite intercepts these requests, transforms your code on the fly (e.g., transpiling JSX, processing CSS), and serves it back. This is why it’s so fast – there’s no massive build step to wait for.

Let’s look at the core configuration file: vite.config.js (or .ts). For a basic React setup, it might look like this:

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

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

The defineConfig function is a helper that provides type hints. The plugins array is where you add Vite plugins. @vitejs/plugin-react is essential for React projects; it handles JSX transformation and Fast Refresh. The resolve.alias section is a common pattern to set up path aliases, allowing you to import modules from a root directory (like src) without specifying the full path (e.g., import MyComponent from '@/components/MyComponent').

When you’re ready to build for production, you run:

npm run build

This command triggers Vite’s production build process. Unlike the development server, this does involve bundling and optimization. Vite uses Rollup under the hood for this. It will generate highly optimized static assets (HTML, CSS, JavaScript) in a dist folder, ready to be deployed to any static host. This build process is significantly faster than traditional bundlers like Webpack because Vite leverages native ES modules and modern tooling.

The vite.config.js file is also where you configure the production build. For example, to specify the base path for your assets in production (useful if deploying to a sub-directory like my-app.com/my-project/), you’d add:

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'),
    },
  },
  base: '/my-project/', // <-- added this line
});

When you run npm run build with this configuration, all generated assets will have their paths prefixed with /my-project/.

One of the most overlooked aspects of Vite’s development server is how it handles hot module replacement (HMR). It’s not just about updating the UI; it’s about preserving the application’s state. When you edit a file, Vite analyzes the import graph and only re-evaluates the modules that are affected. For component-level changes, it often injects the updated code directly into the running module without re-rendering the entire component tree, leading to near-instantaneous updates and the preservation of component state, like form inputs or scroll positions.

After setting up your project and getting the dev server running, the next logical step is understanding how to integrate different types of assets, like images and fonts.

Want structured learning?

Take the full Vite course →