Migrate to Vite from Create React App (CRA)

Robin Wieruch

A quick migration guide to Vite from Create React App, because (apart from Next.js) Vite is the natural successor of CRA for creating a modern React application as SPA.

First, install Vite and all React related libraries (here: Vite’s React Plugin) as development dependencies:

sh
npm install vite @vitejs/plugin-react --save-dev

Second, uninstall create-react-app’s dependency:

sh
npm uninstall react-scripts

Third, adjust your package.json to use the following new scripts:

json
"scripts": {
  "start": "vite",
  "build": "vite build",
  "serve": "vite preview"
},

Fourth, rename all extensions of files which are using JSX from “.js” to “.jsx”, because Vite is explicit with file extensions. If you are using TypeScript, perform the same task from “.ts” to “.tsx”. The following demonstrates it with the App.js file on the command line:

sh
mv src/App.js src/App.jsx
mv src/index.js src/index.jsx

If you are not renaming all your React/JSX related files this way, essentially all files that are using angle brackets, you may get the following or a similar error:

  • The JSX syntax extension is not currently enabled
  • The esbuild loader for this file is currently set to “js” but it must be set to “jsx” to be able to parse JSX syntax. You can use loader: { ".js": "jsx" } to do that.

Fifth, create a vite.config.js file in your Vite + React project’s root directory:

sh
touch vite.config.js

And add the following implementation details to it. Essentially we want to keep the same output directory for the build as we had before with create-react-app. In addition, we want to use Vite’s React Plugin:

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

export default defineConfig(() => {
  return {
    build: {
      outDir: 'build',
    },
    plugins: [react()],
  };
});

Sixth, move the public/index.html into the project’s root folder, because Vite expects it there:

sh
mv public/index.html .

Afterward, remove all %PUBLIC_URL% occurrences in the index.html file.

html
- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
+ <link rel="icon" href="/favicon.ico" />

{/* do this for all occurrences  */}

Last, link the src/index.js file in your moved index.html file the following way:

html
<body>
  <div id="root"></div>
  <script type="module" src="/src/index.jsx"></script>
</body>

That’s it. If you have been using a create-react-app project without any further configuration (e.g. a fresh create-react-app installation), you are ready to start your new Vite based React application with npm start.

However, there may be additional steps needed which I want to outline next in case your create-react-app uses more configurations.


  • If you want to keep using ESLint in Vite as you have used it in create-react-app, follow this Vite + React + ESLint tutorial.
  • If you want to keep using TypeScript in Vite as you have used it in create-react-app, follow this Vite + React + TypeScript tutorial. Optionally follow this ESLint + Prettier tutorial afterward.
  • If you want to keep using react-testing-library in Vite as you have used it in create-react-app, follow this Vite + React + React Testing Library tutorial.
  • If you are using create-react-app’s (CRA’s) environment variables, you need to replace all REACT_APP occurrences with VITE.
  • If you are using process.env in your React project, replace it with import.meta.env.

Troubleshooting create-react-app to Vite migration …

  • If you get ReferenceError: process is not defined from a library, check if it runs with the following workaround:
javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig(() => {
  return {
    // https://github.com/vitejs/vite/issues/1973#issuecomment-787571499
    define: {
      'process.env': {},
    },
    build: {
      outDir: 'build',
    },
    plugins: [react()],
  };
});
  • If you want to keep using SVGs in your Vite project, install vite-plugin-svgr as development dependency. Then include it in Vite’s configuration file:
javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';

export default defineConfig(() => {
  return {
    build: {
      outDir: 'build',
    },
    plugins: [
      react(),
      // svgr options: https://react-svgr.com/docs/options/
      svgr({ svgrOptions: { icon: true } }),
    ],
  };
});

// which allows you to import SVGs as React components
// import { ReactComponent as MyIcon } from './my-icon.svg';
  • If you want to use alias imports in your Vite project, define them the following way:
javascript
import path from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from 'vite-plugin-svgr';

export default defineConfig(() => {
  return {
    resolve: {
      alias: {
        '~': path.resolve(__dirname, './src'),
      },
    },
    build: {
      outDir: 'build',
    },
    plugins: [react()],
  };
});

// which allows you to import from folders under the /src folder
// import Button from '~/components/Button';
  • If you have to support Emotion in your Vite project:
javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig(() => {
  return {
    build: {
      outDir: 'build',
    },
    plugins: [
      react({
        jsxImportSource: '@emotion/react',
        babel: {
          plugins: ['@emotion/babel-plugin'],
        },
      }),
    ],
  };
});
  • If you want to open the browser upon server start, use the following Vite config:
javascript
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig(() => {
  return {
    server: {
      open: true,
    },
    build: {
      outDir: 'build',
    },
    plugins: [react()],
  };
});

That’s essentially it from my side. If you happen to know any other essential troubleshooting hints, let me know!

Never Miss an Article

Join 50,000+ developers getting weekly insights on full-stack engineering and AI.

AI Agentic UI Architecture React Next.js TypeScript Node.js Full-Stack Monorepos Product Engineering
Subscribe on Substack

High signal, low noise. Unsubscribe at any time.