Explore Blogs
Migrating from Create React App (CRA) to Vite: A complete guide

Create React App served its purpose, but modern development needs better speed, flexibility, and transparency. Vite delivers on all fronts. In this post, you'll learn how to migrate your existing CRA project to Vite — including support for React Router, Redux or Zustand, TypeScript, testing with Vitest, Sass, PWA, and ESLint/Prettier.
If you've built a react app with Create React App (CRA), chances are you've started running into its limitations — or you've heard the ecosystem is moving on. CRA is officially deprecated, and Vite has quickly become the go-to replacement for a faster, modern development experience. If you're looking to migrate an existing CRA app to Vite, this guide is for you.
For TypeScript users, the setup instructions can be found at the bottom of this post.
Why to migrate to Vite?
Create React App gave you a zero-config starting point, but that convenience came with long build times, outdated dependencies, and a rigid Webpack setup. Vite solves those issues by leveraging native ES modules and lightning-fast bundling via ESBuild.
With Vite, you get:
- Near-instant dev server startup
- Fast hot module replacement (HMR)
- Cleaner and more modern configuration
- Better support for modern libraries like React Router v6, Zustand, and Vitest
If you're ready to switch, here's how to do it properly.
Clean up the CRA boilerplate
Before you migrate, remove CRA-specific files that Vite won't use. These include:
reportWebVitals.js
setupTests.js
(you’ll replace this later)logo.svg
and any default CRA images- The service worker files, unless you plan to use PWA
Also simplify your src/main.jsx
(or index.js
) to remove unnecessary imports.
Install Vite and React dependencies
First, uninstall react-scripts
:
npm uninstall react-scripts
Then install Vite and core React libraries:
npm install --save-dev vite
npm install react react-dom
You'll also want the Vite plugin for React (which handles Fast Refresh and JSX):
npm install --save-dev @vitejs/plugin-react
Create a vite.config.js
This file replaces CRA's invisible Webpack config. Here's a basic Vite config to get started:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
});
You can add more config later if needed — Vite is very flexible.
Move and edit your index.html
Vite doesn't use the public
folder in the same way as CRA. Move public/index.html
to the root of your project and update it like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>My Vite React App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
This gives Vite full control over your HTML file and lets you take advantage of its fast refresh and module loading features.
Set up react router
If your app uses React Router, you don't need to change much — just make sure your main.jsx
wraps the app in a BrowserRouter
:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Install it if you haven't yet:
npm install react-router-dom
Also, make sure to handle Vite's dev server fallback correctly by adding this to your vite.config.js
:
server: {
historyApiFallback: true,
}
Integrate redux or zustand (Optional)
Redux
If you use Redux, your setup won't change much. Just reinstall the packages:
npm install redux react-redux
Wrap your app in the <Provider>
like you did in CRA:
import { Provider } from 'react-redux';
import store from './store';
<Provider store={store}>
<App />
</Provider>;
Just make sure to replace any process.env.NODE_ENV
with import.meta.env.MODE
.
Zustand
Zustand works out of the box with Vite, no changes required:
npm install zustand
Keep using it like you did in CRA — Vite plays well with modern state libraries.
Set up testing with Vitest
CRA uses Jest, but Vite doesn't. Instead, install Vitest, which is faster and more Vite-native:
npm install --save-dev vitest @testing-library/react jsdom
Update vite.config.js
:
test: {
environment: 'jsdom',
},
Create a vitest.setup.js
if you need to configure testing-library, and update your test scripts in package.json
:
"scripts": {
"test": "vitest"
}
Vitest uses the same test syntax as Jest, so most of your tests will work without modification.
Add Sass and CSS modules support
Vite has built-in support for CSS modules and works great with Sass.
Install Sass:
npm install sass
Then import .scss
or .module.scss
files like this:
import styles from './Button.module.scss'
<button className={styles.primary}>Click</button>
No extra config needed.
ESLint and Prettier setup
Vite doesn't include ESLint by default. If you had ESLint and Prettier in CRA, reinstall them:
npm install --save-dev eslint prettier eslint-plugin-react eslint-config-prettier
Create .eslintrc.json
:
{
"extends": ["react-app", "plugin:react/recommended", "prettier"]
}
Optional .prettierrc
:
{
"singleQuote": true,
"semi": false
}
Add linting to your scripts:
"lint": "eslint ./src --ext .js,.jsx,.ts,.tsx"
Add PWA support (Optional)
If your CRA app used a service worker, you can replicate that with vite-plugin-pwa
.
Install the plugin:
npm install --save-dev vite-plugin-pwa
Update your Vite config:
import { VitePWA } from 'vite-plugin-pwa'
export default defineConfig({
plugins: [react(), VitePWA()]
})
Create a manifest.json
and add your app icons in public/
.
Update environment variables
CRA uses the REACT_APP_
prefix, but Vite uses VITE_
.
So this:
REACT_APP_API_URL=https://example.com
Becomes:
VITE_API_URL=https://example.com
In your code, use:
import.meta.env.VITE_API_URL
Package scripts
Update your package.json
scripts:
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "vitest",
"lint": "eslint ./src"
}
Migrate to TypeScript
If your CRA project was using TypeScript, migrating it to Vite is straightforward. Vite supports TypeScript out of the box without the need for Babel or a custom config.
Install required types
You'll need to add these dev dependencies:
npm install --save-dev typescript @types/react @types/react-dom
CRA already generated a tsconfig.json
, but if you're starting fresh, you can let Vite scaffold one:
npx vite --template react-ts
Or manually create a tsconfig.json
with:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"jsx": "react-jsx",
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src"]
}
Rename files to .tsx
Make sure your entry file is main.tsx
instead of main.jsx
, and rename any other .js
or .jsx
files that contain JSX to .tsx
.
Update vite.config.js
to recognize .ts
files if needed (though the default is fine for most setups).
Deployment
After building your app (npm run build
), you'll get a dist/
folder. This can be deployed on Netlify, Vercel, Cloudflare Pages, or any static hosting service.