Skip to content
React rc ecosystem 5 min read

Build Tools (Vite)

Modern React apps almost never ship raw files to the browser. Your JSX, TypeScript, CSS modules, and image imports all have to be transformed and bundled first, and during development you want that work to happen in milliseconds so the page updates the instant you hit save. The tool that does this is your build tool, and for new React projects in 2026 the default answer is Vite. This page covers what Vite does, the engines that power it, how to wire up environment variables, and why the once-ubiquitous Create React App is now deprecated.

Why you need a build tool

Browsers do not understand JSX, and shipping hundreds of unbundled ES modules over the network is slow. A build tool solves three problems at once: it transforms non-standard syntax (JSX, TypeScript) into plain JavaScript, it bundles and optimizes your code for production, and it gives you a dev server with Hot Module Replacement (HMR) so edits appear without a full page reload. Vite does all three, and does the dev part exceptionally fast.

Getting started with Vite

The fastest way to scaffold a project is the official create-vite initializer. It generates a ready-to-run React app with sensible defaults.

npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev

For TypeScript, swap the template to react-ts. After npm run dev, Vite prints the local URL:

Output:

  VITE v6.0.0  ready in 312 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help

The generated package.json exposes three scripts you will use constantly:

ScriptCommandPurpose
devviteStart the dev server with HMR
buildvite buildProduce an optimized production bundle in dist/
previewvite previewServe the built dist/ locally to sanity-check production output

How Vite works under the hood

Vite’s speed comes from using two different engines for two different jobs.

In development, Vite serves your source files over native ES modules. There is no upfront bundling step — the browser requests each module, and Vite transforms it on demand. Those transforms (JSX and TypeScript stripping) are handled by esbuild, a bundler written in Go that is one to two orders of magnitude faster than JavaScript-based tools. This is why the dev server starts in a few hundred milliseconds regardless of project size.

For production, Vite switches to Rollup, which performs whole-program optimization: tree-shaking to drop dead code, code-splitting into chunks, asset hashing for cache-busting, and minification. You get fast startup in dev and a tightly optimized bundle in production.

Vite pre-bundles your node_modules dependencies with esbuild on first run and caches the result in node_modules/.vite. If a dependency misbehaves after an upgrade, delete that cache (or run vite --force) to rebuild it.

The React plugin (@vitejs/plugin-react) ties it together. A minimal config looks like this:

// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  server: { port: 3000 },
});

Hot Module Replacement

HMR replaces edited modules in the running app without reloading the page, preserving component state. The React plugin enables Fast Refresh, so editing a component updates it in place. You generally get HMR for free, but if you write a module that needs custom handling you can opt in via the import.meta.hot API:

export function counter() {
  let value = 0;
  return () => (value += 1);
}

if (import.meta.hot) {
  import.meta.hot.accept((newModule) => {
    console.log('Module updated without a full reload', newModule);
  });
}

Environment variables

Vite exposes env vars on import.meta.env rather than process.env. To prevent leaking secrets into the client bundle, only variables prefixed with VITE_ are exposed to your code. Define them in .env files at the project root:

# .env
VITE_API_URL=https://api.example.com
SECRET_KEY=never-exposed
function App() {
  // Available in the browser because of the VITE_ prefix.
  const apiUrl = import.meta.env.VITE_API_URL;

  // import.meta.env.SECRET_KEY is undefined in the client — by design.
  return <p>Talking to {apiUrl}</p>;
}

Vite also provides built-in flags: import.meta.env.MODE, import.meta.env.DEV, and import.meta.env.PROD. Use .env.development and .env.production for mode-specific values, and never put true secrets in any VITE_-prefixed variable.

Why Create React App is deprecated

Create React App (CRA) was the standard scaffolder for years, but the React team officially deprecated it in February 2025 and the React documentation no longer recommends it. CRA was built on webpack with a slow, full-bundle dev server; cold starts and rebuilds grew painful as apps scaled. It also fell behind on maintenance, shipping outdated dependencies and leaving security audit warnings unaddressed.

Create React AppVite
Dev enginewebpack (bundle everything)esbuild + native ESM
Cold startSeconds, grows with app size~Sub-second, near-constant
Production bundlerwebpackRollup
StatusDeprecated (2025)Actively maintained default

The official migration path is to either move to a full framework like Next.js or React Router, or, for a plain single-page app, switch to Vite. Migration is usually quick: install vite and @vitejs/plugin-react, move index.html to the project root with a <script type="module" src="/src/main.jsx"> entry, and rename process.env.REACT_APP_* variables to import.meta.env.VITE_*.

Best Practices

  • Scaffold new SPAs with create-vite; reach for Next.js or React Router when you need routing, SSR, or data loading conventions.
  • Prefix any client-readable env var with VITE_, and keep real secrets server-side — never in the client bundle.
  • Run npm run preview before deploying to test the actual production build, not just the dev server.
  • Add vite --force to your troubleshooting toolkit when a dependency upgrade leaves a stale pre-bundle cache.
  • Keep vite.config.js lean; reach for plugins only when you need them, since each one runs on every transform.
  • Migrate off Create React App — it is deprecated and unmaintained.
Last updated June 14, 2026
Was this helpful?