# How to Transition from CRA to Vite: A Step-by-Step Guide

**CRA** has been one of my favorite tool. It gave us superpower to spin up react app with out of the box support for *eslint , postcss , testing library,Web vitals* and many more..

Since **CRA** has been depreciated and now **React team** recommend using frameworks like next.js, remix…. which are not only huge, but they have framework specific features.

But these are not necessary for small projects that we already built. Or we just want the same flavour as **CRA** gave as. Why not migrate to **Vite**.

As you already know about **Vite**. if not then, **Vite** is a modern front-end build tool that offers fast development and optimized production builds.

**CRA** used to depend upon **webpack** for its build task and all, but it has huge configuration under the hood.

## **Migration steps**

These migration steps assume that we have a CRA project with Typescript.

1. Removing CRA dependencies
    
2. Installing Vite and its dependencies
    
3. Moving index.html
    
4. Adding vite.config.ts
    
5. Replacing react scripts to Vite scripts
    
6. Fixing the env
    

**Optional steps**

7. Configuring eslint
    
8. Setting up tailwind for Vite
    

## 1\. Removing the CRA dependencies

First step includes removing all the CRA dependencies which is surprisingly only react-scripts but behind the scenes it has a lot of dependencies. Now, it feels like react-scripts is bloaty. But it is the thing that made **React** this much popular. It made react apps do the things which were easily not available to setup from scratch.

```bash
npm rm react-scripts
```

But for now, goodbye react-scripts. we will miss you. JSX has never been evolved if you were not there.

## 2\. Installing Vite and its dependencies

Now moving towards the second step, which is letting the damn thing in. Installing the Vite. Vite will be installed as dev dependency since it is only required for building and development purpose.

```bash
npm install vite -D
```

Only Vite is not enough. Since Vite is bundler, which is not specifically for react, so we need to install its additional dependencies for **React app**.

1. `@vitejs/plugin-react-swc` – A faster, Rust-based plugin for handling React (recommended over the older Babel-based `@vitejs/plugin-react`).
    
2. `vite-tsconfig-paths` – Helps Vite resolve TypeScript path aliases.
    

```bash
npm install @vitejs/plugin-react-swc vite-tsconfig-paths
```

*Note: Depending on your specific needs, you can choose a different plugin from the official Vite plugins* [*documentation.*](https://main.vitejs.dev/plugins/)

## 3\. Moving index.html

Index.html file is not same in **CRA** and **Vite.**

In a **Create React App (CRA)** project, the `index.html` file is located inside the `public/` folder. It serves as the main HTML template where the React app is injected.

**Key Points:**

* CRA **does not use this file for JavaScript imports**; instead, React is injected via `index.js` or `index.tsx`.
    
* `%PUBLIC_URL%` is a placeholder that gets replaced with the actual public URL at build time.
    

So, move `index.html` file in `public/` folder to the root of your project.

And in **Vite’s** `index.html` is directly used as the entry point and includes the script reference manually!

```xml
<!-- index.html -->
<body>
  .................
  .................

  <!--    Add this script tag before closing body tag -->
  <script type="module" src="/src/index.tsx"></script>
</body>
```

And replace `%PUBLIC_URL%` with / or better use dynamic path to ensure that the assets are referenced correctly in **Vite**, as Vite does not process `%PUBLIC_URL%` like CRA does.

* CRA uses `%PUBLIC_URL%` to dynamically inject the base URL, useful when deploying to subdirectories.
    
* Vite **doesn't need** `%PUBLIC_URL%`; it serves static assets directly from `/public/`.
    

```xml
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

    <!-- Change like this -->
    ......
    <link rel="manifest" href="/manifest.json" /> 

    <!-- Or better like this -->
    ........
    <link rel="manifest" href="manifest.json" />/>
```

## 4\. Adding vite.config.ts

create a `vite.config.ts` file in root folder of your project and configure for **React app** using `@vitejs/plugin-react-swc` plugin.

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

// https://vitejs.dev/config/
export default defineConfig({
  base: '/',
  plugins: [react()]
})
```

## 5\. Replacing react scripts to Vite scripts

Updating the `scripts` section in `package.json` is crucial.

```json

// from this  
"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },

// to this
 "scripts": {
    "start": "vite",
    "build": "tsc && vite build",
    "serve": "vite preview"
}
```

Ensure your `package.json` contains:

```json
{
  "type": "module"
}
```

## 6\. fixing the env

In Vite, environment variables **must start with** `VITE_` to be exposed to the frontend.

### **Rename Environment Variables**

Replace `REACT_APP_` prefixes with `VITE_` in your `.env` file:

```ini
VITE_API_URL=https://api.example.com
VITE_APP_NAME=My Vite App
```

### **Access Environment Variables in Code**

Use `import.meta.env` instead of `process.env`:

```javascript
console.log(import.meta.env.VITE_API_URL)
console.log(import.meta.env.VITE_APP_NAME)
```

### **Enable TypeScript Support for Vite Env Variables**

Create a `vite-env.d.ts` file inside the `src/` directory with the following content:

```bash
/// <reference types="vite/client" />
```

This ensures **TypeScript** recognizes Vite-specific features like `import.meta.env`.

### **Remove Unnecessary React-Specific Files**

If your project has a `react-app-env.d.ts` file inside the `src/` directory, **delete it**, as it's only relevant for Create React App (CRA).

## 7\. Configuring eslint (Optional)

This ESLint setup follows the **Vite starter template**.

### **Install ESLint and Required Plugins**

Run the following command to install ESLint and necessary dependencies:

```bash
npm install eslint globals @eslint/js typescript-eslint eslint-plugin-react-hooks eslint-plugin-react-refresh
```

### **Create** `eslint.config.js`

In the root of your project, create a new file named `eslint.config.js` and add the following configuration:

```bash
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";

export default tseslint.config(
  { ignores: ["dist"] },
  {
    extends: [js.configs.recommended, ...tseslint.configs.recommended],
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      ...reactHooks.configs.recommended.rules,
      "react-refresh/only-export-components": [
        "warn",
        { allowConstantExport: true },
      ],
    },
  }
);
```

### **Alternative: Using ESLint Official Setup**

If you prefer the [**official ESLint setup**](https://eslint.org/docs/latest/use/getting-started#configuration), you can run:

```bash
npm init @eslint/config@latest
```

However, this setup is **stricter** and may not be ideal for all projects.

## 8\. Setting up tailwind for Vite (Optional)

If you're already using Tailwind CSS, you'll need to reconfigure it. For a fresh installation, refer to the **official** [**Tailwind CSS documentation**](https://tailwindcss.com/docs/installation/using-vite) for Vite.

### **Install Tailwind CSS for Vite**

Run the following command to install the required dependency:

```bash
npm install @tailwindcss/vite
```

### **Configure Tailwind in** `vite.config.ts`

Update your `vite.config.ts` to include the Tailwind CSS Vite plugin:

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import tailwindcss from '@tailwindcss/vite'

// https://vitejs.dev/config/
export default defineConfig({
  base: '/',
  plugins: [
    react(),
    tailwindcss(),
  ],
})
```

This ensures Tailwind CSS is properly integrated into your Vite-powered React app.
