When to reach for this: Enable the React Compiler for any React 19 project to automatically optimize re-renders. It replaces the need for useMemo, useCallback, and React.memo in the vast majority of cases.
The React Compiler is a build-time tool (Babel plugin) that analyzes your components and hooks, then automatically inserts memoization.
It understands React's rules of hooks and the rules of React (pure rendering, immutable props/state) to determine what values can be safely cached.
The compiler transforms your code to memoize: JSX elements, expensive computations, callback functions, and component re-renders -- roughly equivalent to wrapping things in useMemo, useCallback, and React.memo where appropriate.
It performs fine-grained memoization -- it can memoize individual JSX subtrees within a component, not just the entire return value.
The compiler targets React 19 by default and uses React 19's internal cache API. For React 17 and 18, set target: "17" or target: "18" and install the react-compiler-runtime package.
If the compiler detects code that violates React's rules (e.g., mutating props, side effects during render), it skips that component and leaves it unoptimized. It does not break your code.
You can use the "use no memo" directive at the top of a function to opt out a specific component or hook from compiler optimization.
// babel.config.js -- only compile files with "use memo" directivemodule.exports = { plugins: [ ["babel-plugin-react-compiler", { compilationMode: "annotation", // only compile "use memo" functions }], ],};
// Only this component is compiledfunction OptimizedList({ items }: { items: string[] }) { "use memo"; return ( <ul> {items.map((item) => ( <li key=
Opting out a specific component:
function LegacyComponent({ data }: { data: any }) { "use no memo"; // This component will not be optimized by the compiler // Useful for code that intentionally breaks React rules externalMutableStore.value = data; return <div>{data.label}</div>;}
Health check before adopting:
# Run the health check to see how compatible your codebase isnpx react-compiler-healthcheck --verbose
Mutating objects or arrays during render -- The compiler assumes pure rendering. Mutating props, state, or variables that are shared across renders causes incorrect caching. Fix: Follow React's rules -- always create new objects/arrays instead of mutating. The ESLint plugin catches most violations.
Side effects during render -- Code like console.log(Date.now()) or modifying external variables during render may produce stale results when the compiler caches the output. Fix: Move side effects into useEffect or event handlers.
External mutable stores -- Reading from mutable global variables or stores that React does not track (e.g., a plain global object) may break under compiler optimization. Fix: Use useSyncExternalStore for external mutable state.
Existing useMemo/useCallback not harmful -- If you already have manual memoization, the compiler works with it. You do not need to remove it before enabling the compiler. Fix: Optionally remove manual memoization for cleaner code, but it is not required.
Not all code is compiled -- Components that violate React's rules are silently skipped. You may not notice that a component is unoptimized. Fix: Use eslint-plugin-react-compiler to catch issues and check the compiler's build output for skipped components.
Build time increase -- The compiler adds analysis time to your build. On very large codebases this may be noticeable. Fix: Use the compilationMode: "annotation" option to compile only opted-in components during migration.
For non-Next.js projects, install babel-plugin-react-compiler and add it to your Babel config.
Do I need to remove existing useMemo, useCallback, and React.memo calls?
No. The compiler works alongside existing manual memoization
You can optionally remove them for cleaner code, but it is not required
The compiler will not conflict with or double-memoize these calls
What happens if a component violates React's rules (e.g., mutates props)?
The compiler silently skips that component and leaves it unoptimized
It does not break your code -- the component renders as if the compiler was not enabled
Use eslint-plugin-react-compiler to detect which components are being skipped and why
How do you opt out a specific component from compiler optimization?
function LegacyComponent({ data }) { "use no memo"; // This component will not be optimized externalStore.value = data; return <div>{data.label}</div>;}
The "use no memo" directive is placed at the top of the function body.
How do you gradually roll out the compiler with opt-in mode?