Adding the Compiler to a Build

The compiler is one development dependency and one line of build configuration:

Installing the compiler and the lint rulesShell
npm install -D babel-plugin-react-compiler@latest eslint-plugin-react-hooks@latest

In a Vite 8 25,978 project, @vitejs/plugin-react 6.1.1 exposes the compiler as a Babel 41,624 preset that runs through @rolldown/plugin-babel:

vite.config.js with the React Compiler enabledJavaScript
import { defineConfig } from 'vite';
import react, { reactCompilerPreset } from '@vitejs/plugin-react';
import babel from '@rolldown/plugin-babel';
export default defineConfig({
  plugins: [react(), babel({ presets: [reactCompilerPreset()] })],
});

On older Vite the plugin goes straight to Babel instead, with react({ babel: { plugins: ['babel-plugin-react-compiler'] } }). In a plain Babel setup, 'babel-plugin-react-compiler' must be first in the plugins array, ahead of the JSX transform. Next.js 10,514 has its own switch, covered in Next.js.

The lint rules moved house in the 1.0 release: they now live in eslint-plugin-react-hooks 7.1.1 rather than the separate eslint-plugin-react-compiler, and the recommended-latest preset turns on both the Hook rules and the compiler's diagnostics — set-state-in-render, set-state-in-effect and refs among them. Lint first: every rule it reports is a place the compiler would have to decline.

The compiler options you are most likely to set
Option What it controls Typical value
compilationMode Which functions get compiled 'annotation' for opt-in
target React 7,897 version to emit for '17', '18' or '19'
panicThreshold Code it cannot compile 'none': skip, do not fail
gating Runtime flag for a staged rollout { source, importSpecifierName }
logger Reporting of compiled files logEvent(filename, event)

A React 17 or 18 codebase works too: set target: '17' or '18' and add the react-compiler-runtime package, which supplies the c Hook that React 19 ships natively.

For an existing application, turn it on gradually. compilationMode: 'annotation' compiles only functions whose body starts with the "use memo" directive, so you convert a screen at a time; Babel's overrides option does the same by directory. In the other direction, "use no memo" as a function's first statement excludes it — its compiled output is byte-for-byte its input. A module-level directive covers the file; a function-level one wins.