
How to Set Up a React Project with Vite – Fast and Simple
Vite has revolutionized the React development experience by providing lightning-fast build times and hot module replacement that actually works. While Create React App served us well for years, Vite’s modern approach using native ES modules and esbuild preprocessing delivers development server startup times measured in milliseconds rather than seconds. This guide walks you through setting up a React project with Vite from scratch, covers configuration customization, and shows you how to avoid the most common gotchas that trip up developers making the switch.
Why Vite Outperforms Traditional Build Tools
Vite leverages native ES modules in the browser during development, which means it only needs to transform and serve the files that have actually changed. Traditional bundlers like Webpack rebuild entire dependency graphs even for small changes, leading to increasingly slow development cycles as projects grow.
The performance difference is dramatic. Here’s what you can expect:
Metric | Create React App | Vite | Improvement |
---|---|---|---|
Cold start time | 15-30 seconds | 200-500ms | 30-150x faster |
Hot reload | 1-3 seconds | 50-200ms | 5-60x faster |
Production build | 45-90 seconds | 20-45 seconds | 2-3x faster |
Setting Up Your First Vite React Project
Getting started with Vite is straightforward, but there are several approaches depending on your needs. The quickest method uses Vite’s built-in React template:
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
npm run dev
For TypeScript support (highly recommended for larger projects):
npm create vite@latest my-react-app -- --template react-ts
If you prefer Yarn or pnpm:
# Yarn
yarn create vite my-react-app --template react
# pnpm
pnpm create vite my-react-app --template react
The generated project structure is cleaner than Create React App’s output:
my-react-app/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ ├── App.css
│ ├── App.jsx
│ ├── index.css
│ └── main.jsx
├── index.html
├── package.json
└── vite.config.js
Essential Vite Configuration
The default vite.config.js
works for basic projects, but you’ll likely need customization. Here’s a production-ready configuration that handles common requirements:
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')
}
},
server: {
port: 3000,
open: true,
host: true // Allows access from network
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
router: ['react-router-dom']
}
}
}
},
preview: {
port: 4173,
host: true
}
})
This configuration adds path aliases for cleaner imports, sets up chunk splitting for better caching, and configures the development server for network access – useful when testing on mobile devices or when running on a VPS.
Environment Variables and Production Builds
Vite handles environment variables differently than Create React App. Instead of REACT_APP_
prefixes, Vite uses VITE_
:
# .env.local
VITE_API_URL=https://api.example.com
VITE_APP_VERSION=1.0.0
Access them in your components:
function App() {
const apiUrl = import.meta.env.VITE_API_URL
const isDevelopment = import.meta.env.DEV
return (
<div>
<h1>My App v{import.meta.env.VITE_APP_VERSION}</h1>
{isDevelopment && <p>Running in development mode</p>}
</div>
)
}
For production builds, Vite uses Rollup under the hood, which provides excellent tree-shaking and optimization:
npm run build
The build output includes detailed bundle analysis. You can visualize bundle composition with the rollup-plugin-visualizer:
npm install --save-dev rollup-plugin-visualizer
Add it to your Vite config:
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig({
plugins: [
react(),
visualizer({
filename: 'dist/stats.html',
open: true
})
]
})
Migrating from Create React App
Moving an existing CRA project to Vite requires a few adjustments. Here’s the step-by-step process:
- Move
index.html
frompublic/
to the root directory - Add a script tag pointing to your entry file:
<script type="module" src="/src/main.jsx"></script>
- Rename
src/index.js
tosrc/main.jsx
- Update environment variables from
REACT_APP_
toVITE_
- Replace
process.env
withimport.meta.env
- Install Vite and remove CRA dependencies
# Remove CRA
npm uninstall react-scripts
# Install Vite
npm install --save-dev vite @vitejs/plugin-react
# Update package.json scripts
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}
Common Issues and Troubleshooting
Several issues commonly trip up developers new to Vite:
Import path issues: Vite is stricter about file extensions. You might need to add .jsx
extensions to imports or configure resolve.extensions:
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
Global process variable: Some libraries expect process.env
to exist. Add this to your index.html:
<script>
window.global = window;
window.process = { env: {} };
</script>
Dynamic imports with variables: Vite needs to statically analyze imports. Instead of:
// Won't work
const module = await import(variablePath)
Use explicit paths:
// Works
const modules = {
'component-a': () => import('./ComponentA.jsx'),
'component-b': () => import('./ComponentB.jsx')
}
const module = await modules[componentName]()
Port conflicts: If port 5173 is in use, Vite automatically tries the next available port. Lock it down in your config if needed for CI/CD or when deploying to dedicated servers.
Advanced Features and Integrations
Vite’s plugin ecosystem rivals Webpack’s in functionality. Here are some essential plugins for React development:
npm install --save-dev @vitejs/plugin-react-swc
Replace the default React plugin with SWC for even faster builds:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [react()]
})
For PWA support:
npm install --save-dev vite-plugin-pwa
// vite.config.js
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [
react(),
VitePWA({
registerType: 'autoUpdate',
workbox: {
globPatterns: ['**/*.{js,css,html,ico,png,svg}']
}
})
]
})
Performance Optimization Tips
Vite is fast by default, but you can squeeze out additional performance:
- Use
@vitejs/plugin-react-swc
instead of the default Babel-based plugin - Enable dependency pre-bundling for large dependencies in
optimizeDeps.include
- Configure proper chunk splitting to maximize browser caching
- Use dynamic imports for route-based code splitting
- Enable gzip compression in your production server configuration
For large monorepos or complex projects, consider these optimizations:
export default defineConfig({
optimizeDeps: {
include: ['react', 'react-dom', 'lodash-es'],
exclude: ['@your-org/large-internal-package']
},
build: {
rollupOptions: {
output: {
manualChunks: (id) => {
if (id.includes('node_modules')) {
return 'vendor'
}
if (id.includes('src/pages')) {
return 'pages'
}
}
}
}
}
})
The development experience with Vite transforms how you build React applications. The near-instantaneous feedback loop keeps you in flow state, while the production builds remain optimized and performant. Once you experience sub-second hot reloads and lightning-fast server startup, going back to traditional bundlers feels like switching from an SSD to a spinning hard drive.
For teams working with larger applications or microservices architectures, Vite’s speed improvements compound significantly. The time saved during development cycles adds up quickly, especially when combined with modern hosting solutions that can take full advantage of Vite’s optimized build output.
Check out the official Vite documentation for advanced configuration options and the latest features. The Awesome Vite repository maintains a comprehensive list of plugins and community resources to extend your setup further.

This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.
This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.