Migrating Create React App to Vite: Step by Step
AI generated
</>
{ }
React · Build Tooling · Vite · Migration
Migrating Create React App to Vite
the step by step guide

Create React App is no longer maintained, but an existing project does not migrate itself. Whoever migrates Create React App to Vite has to transfer configuration, environment variables, proxy setup and tests one by one to end up with a faster dev server and no broken builds.

17 min read vite.config · import.meta.env · Vitest Vite 6 · React 19

1. Why migrating Create React App to Vite is necessary now

Create React App has been officially archived, no longer receives updates for new React versions, and is no longer recommended by the React documentation. Whoever runs an existing application will sooner or later have to migrate Create React App to Vite, because react-scripts internally builds on outdated versions of Webpack, Babel and ESLint, which accumulate security vulnerabilities and eventually stop being maintained.

The second driver is developer experience. The dev server of Create React App often takes several seconds to start for mid sized projects, with noticeable delays for hot module replacement. Vite uses native ES modules in the browser during development and therefore usually starts in under a second, which is immediately noticeable on every save.

The third reason: many modern libraries now test and document their setup guides exclusively for Vite, while Create React App setups often only survive as community workarounds. Whoever migrates Create React App to Vite also regains access to current documentation and community support for new tools.

2. Preparation: dependencies and the base setup

Before the actual migration, it pays off to take stock of every react-scripts specific feature in the project: environment variables with the REACT_APP_ prefix, proxy configuration in package.json, as well as CRACO or react-app-rewired overrides if the project has already customized the Webpack configuration. This list determines the actual migration effort far more than pure project size.

Vite is then installed alongside react-scripts, so both toolchains can coexist in the same repository for a transition period. This allows testing the new dev server while the existing build keeps working, until the migration is fully complete.


# Install Vite and the React plugin alongside the existing CRA toolchain
npm install --save-dev vite @vitejs/plugin-react

# Vitest replaces Jest as the test runner in a later step
npm install --save-dev vitest @vitest/ui jsdom

# react-scripts, react-app-rewired or craco can be removed once
# vite.config.ts fully replaces their functionality
npm uninstall react-scripts

3. vite.config.ts instead of react-scripts

The core of the migration is the new vite.config.ts, which replaces everything that was previously hidden implicitly inside react-scripts. While Create React App had no visible configuration file, Vite makes every setting explicit, which initially means more code, but is considerably easier to debug long term because nothing hides in a black box anymore.


// vite.config.ts: explicit replacement for the hidden react-scripts config
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      // Mirrors a CRA jsconfig.json "baseUrl": "src" setup
      '@': path.resolve(__dirname, './src'),
    },
  },
  server: {
    port: 3000, // Match the old CRA default port for a familiar dev workflow
    open: true,
  },
  build: {
    outDir: 'build', // Keep the output directory CI/CD pipelines already expect
    sourcemap: true,
  },
});

Whoever migrates Create React App to Vite and previously used CRACO or react-app-rewired can consolidate all overrides into this one file, instead of managing them through a separate overrides package. This often reduces the number of build tool dependencies in the project by two to three packages.

4. Environment variables from REACT_APP to VITE

Create React App expects environment variables with the REACT_APP_ prefix, accessible via process.env.REACT_APP_API_URL. Vite instead uses the VITE_ prefix and exposes the values through import.meta.env.VITE_API_URL. This rename affects every place in the code that accesses environment variables and is most reliably handled with a project wide search and replace operation.


# .env file: rename the prefix from REACT_APP_ to VITE_
# BEFORE (Create React App)
REACT_APP_API_URL=https://api.example.com
REACT_APP_FEATURE_FLAG_NEW_CHECKOUT=true

# AFTER (Vite)
VITE_API_URL=https://api.example.com
VITE_FEATURE_FLAG_NEW_CHECKOUT=true

# Search and replace across the codebase:
grep -rl "process.env.REACT_APP_" src/ \
  | xargs sed -i 's/process\.env\.REACT_APP_/import.meta.env.VITE_/g'

A common mistake during this migration: developers forget that import.meta.env, unlike process.env, is only statically replaced at build time and does not allow dynamic keys. Access like import.meta.env[dynamicKey] does not work reliably and must be replaced with explicit, statically known variable names.

5. Moving index.html, the public folder and assets

In Create React App, index.html lives in the public folder and is treated by Webpack as a template that replaces placeholders like %PUBLIC_URL%. With Vite, index.html moves to the project root and becomes the entry point of the build process itself, including a direct <script type="module" src="/src/main.tsx"> tag instead of a Webpack injected bundle.

The public folder remains in Vite for static assets meant to be copied unchanged, but %PUBLIC_URL% placeholders must be replaced with relative paths, because Vite does not know this Webpack specific templating. Images and fonts previously imported from src keep working unchanged in Vite, since both tools support the ES module import system for assets.

6. Proxy setup for local API development

Many Create React App projects use the simple "proxy": "http://localhost:8080" field in package.json to forward API requests to a backend during local development. Vite offers a considerably more flexible, but also more explicit, proxy configuration directly in the server block of vite.config.ts, allowing different targets per path prefix.


// vite.config.ts: proxy replaces the simple "proxy" field from package.json
export default defineConfig({
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true,
      },
      '/ws': {
        target: 'ws://localhost:8080',
        ws: true, // WebSocket proxying needs to be enabled explicitly
      },
    },
  },
});

7. Migrating Jest to Vitest

React Testing Library tests barely change when porting from Jest to Vitest, because Vitest deliberately provides a compatible API. The test functions describe, it and expect stay identical, which makes migrating the tests themselves the easiest subtask when migrating Create React App to Vite. The more involved part is the Jest configuration, which needs to be translated into a test section of vite.config.ts.

Mock functions with jest.mock() get replaced by vi.mock(), and global mock functions like jest.fn() become vi.fn(). A project wide search and replace handles most of these renames automatically, while more complex mock setups with module hoisting need manual adjustment.

8. Common pitfalls after the migration

The most common mistake after migrating Create React App to Vite concerns absolute imports that previously worked through jsconfig.json or tsconfig.json with baseUrl. Vite does not automatically read this TypeScript specific configuration for runtime module resolution, which is why the alias configuration must additionally be duplicated in vite.config.ts, as shown in the example in section three.

A second pitfall involves CSS modules and global stylesheets, which in rare cases produce different naming conventions for generated classes between Webpack and Vite. Visual regression tests before and after the migration reliably catch such differences before they become visible in production.

9. Create React App and Vite compared directly

The table below summarizes the concrete differences relevant in practice when migrating Create React App to Vite.

Aspect Create React App Vite Impact
Dev server start Several seconds Under one second Native ES module serving
Environment variables REACT_APP_ prefix VITE_ prefix Project wide rename needed
Configuration Hidden in react-scripts Explicit in vite.config.ts Better debuggability
Test runner Jest Vitest, compatible API Tests run almost unchanged
Maintenance status Archived, no updates Actively developed Long term safety

The table shows that migrating Create React App to Vite is not a pure performance upgrade, it also secures long term maintainability. An archived build tool with no security updates is a growing risk for production applications, which clearly justifies the migration.

Mironsoft

React build tooling, Vite migrations and CI/CD modernization

Still running on an archived Create React App setup?

We transfer your configuration, environment variables and tests from Create React App to Vite and future proof your build against upcoming React versions.

Migration Audit

Inventory of all CRACO, rewire and proxy configurations

Vite Setup

Complete vite.config.ts with alias, proxy and build settings

Test Relocation

Jest to Vitest migration including mock functions and CI pipeline

10. Summary

Whoever wants to migrate Create React App to Vite should start with an inventory of every react-scripts specific feature: environment variables, proxy configuration and any CRACO overrides. The new vite.config.ts makes everything explicit that was previously implicit, environment variables move from the REACT_APP_ to the VITE_ prefix, and index.html itself becomes the entry point instead of a template in the public folder.

Proxy configuration, test relocation from Jest to Vitest, and alias resolution for absolute imports are the parts requiring the most care. The payoff of the migration is a dev server that starts in under a second, and a build tool that, unlike the archived Create React App, is actively developed and keeps pace with new React versions.

Migrating Create React App to Vite: The Essentials

Configuration

vite.config.ts replaces react-scripts, CRACO and react-app-rewired in a single file.

Environment variables

REACT_APP_ becomes VITE_, process.env becomes import.meta.env throughout the code.

Tests

Vitest offers a Jest compatible API, test functions stay largely unchanged.

Result

Dev server starts in under a second instead of several, an actively maintained build tool.

11. FAQ: Migrating Create React App to Vite

1How long does the migration take?
One to two days without CRACO overrides, up to a week with complex customization.
2Do all tests need to move at once?
No, Vitest can be installed alongside Jest for a gradual move.
3What happens to REACT_APP_ variables?
Renamed to VITE_ in the .env file and at every process.env access in the code.
4Does the old proxy still work?
No, replaced by server.proxy in vite.config.ts with more control.
5Do I still need tsconfig for aliases?
Yes for type checking, plus the same alias in vite.config.ts under resolve.alias.
6Is index.html handled differently?
Yes, moves to the project root and becomes the entry point with a direct script tag.
7Is Vite slower for production builds?
No, Rollup is usually comparably fast or faster than the Webpack build.
8What do I do with CRACO overrides?
Translate every customization individually into a Vite equivalent, no automatic tool exists.
9Can both toolchains run in parallel?
Yes, both coexist during the transition while the new dev server is tested.
10Does the folder structure change?
Barely, src and public remain, the most visible difference is the new vite.config.ts in root.