Overview
React Compiler 1.0 (released 2025-10-07; babel-plugin-react-compiler 1.0.0 is still the latest npm release on 2026-10-01) memoizes components and hooks at build time, which removes most hand-written useMemo, useCallback, and memo(). It is versioned separately from React and is opt-in: React 19 alone does nothing. The compiler supports React 17 and up. New Expo SDK 54+ apps enable it by default; Next.js and Vite need explicit setup.
Treat the compiler as opt-in
Decide the stance per project: enable it and write plain code, or leave it off and keep disciplined manual memoization. Without the plugin, every useMemo you delete is a real regression. On React 17 or 18, install react-compiler-runtime and set target in the plugin options. In an existing codebase, leave current memoization in place; removing it can change compiled output.
Enable it through the build, then verify
The Babel plugin must run first in the pipeline. Prefer the framework flag over a hand-written Babel config.
// next.config.ts (Next.js 16: stable, off by default)
export default { reactCompiler: true };// vite.config.js (@vitejs/plugin-react 6+)
import react, { reactCompilerPreset } from "@vitejs/plugin-react";
import babel from "@rolldown/plugin-babel";
export default { plugins: [react(), babel({ presets: [reactCompilerPreset()] })] };Next.js leaves it off by default; enabling it raises dev and build times because the compiler relies on Babel. Next.js 16.3 adds an experimental Rust port inside Turbopack (experimental.turbopackRustReactCompiler: true) that reduces that cost.
Confirm it worked: compiled components show a “Memo ✨” badge in React DevTools. Install eslint-plugin-react-hooks (v7); its compiler rules sit in the recommended-latest preset and flag components the compiler will skip. A skipped component is safe, only unoptimized. If test coverage is thin, pin the exact compiler version, because memoization changes between releases can alter behavior.
Keep manual memoization where the compiler cannot decide
- A memoized value used as an Effect dependency, so the Effect does not refire when only identity changed.
- An expensive function called from a component. The compiler memoizes components and hooks only, and its cache is not shared across components; give the function its own cache.
- A component you must exclude: add the
"use no memo"directive inside it.
Outside these cases, write the plain expression. react-performance holds the profile-first order of operations.
Roll out incrementally
Do not enable it repo-wide in one change. Pick one of three strategies from the React docs:
- Directory scope: apply the plugin through Babel
overrideswith atestglob and widen the glob as slices pass. - Annotation mode: set
compilationMode: "annotation"and add"use memo"to chosen components. - Runtime gating: wire
gatingto a feature flag to A/B the compiled build.
Run tests and the Profiler on each slice, and watch for components that quietly relied on unstable references or mutated props during render.