React Compiler Explained: What It Optimizes Automatically

React Compiler memoizes components and hooks at build time, removing most manual useMemo, useCallback, and React.memo calls. Learn what it optimizes and how to enable it.

6 min read

React Compiler is a build-time tool that automatically memoizes components and hooks. It removes the need for manual useMemo, useCallback, and React.memo in most code. It is stable, tested in production, and optional: you enable it through your build tool rather than installing a new runtime library.

What it optimizes

The compiler focuses on two jobs. It skips cascading re-renders, so a parent update no longer re-renders every child by default. It also memoizes expensive calculations that happen inside components and hooks.

  • It optimizes components and hooks.
  • It does not memoize every standalone function.
  • Its memoization is not shared between different components.

For example, when a parent's state changes, only the parts of the tree that actually depend on the new values re-render, instead of every child below the parent.

For a calculation that lives in a plain helper outside any component, the compiler leaves it alone, and you may still want to profile that code separately.

How to enable it

Install the compiler as a development dependency. It is designed for React 19 and supports React 17 and 18 through configuration.

bashbash
npm install -D babel-plugin-react-compiler@latest

The compiler is a Babel plugin. It must run first in the plugin list so it sees the original source before other transforms.

index.jsindex.js
module.exports = {
  plugins: ["babel-plugin-react-compiler"],
};

Vite users can use the reactCompilerPreset from version 6 of @vitejs/plugin-react, and Next.js enables the compiler through its configuration from version 15.3.1 onward. Check the current React Compiler installation guide for the exact wiring of your build tool. When you already have a Babel config, place the plugin ahead of any preset or plugin that rewrites JSX.

What changes in your code

Before the compiler, a list component carries three layers of manual memoization to stay fast.

App.jsxApp.jsx
import { memo, useCallback, useMemo } from "react";
 
const ExpensiveList = memo(function ExpensiveList({ items, onSelect }) {
  const sorted = useMemo(() => sortItems(items), [items]);
  const handleSelect = useCallback((id) => onSelect(id), [onSelect]);
 
  return (
    <ul>
      {sorted.map((item) => (
        <li key={item.id} onClick={() => handleSelect(item.id)}>
          {item.title}
        </li>
      ))}
    </ul>
  );
});

Here sortItems returns a sorted copy of the items array, and the inline arrow is a small wrapper around the handler. With the compiler enabled, you write the same component without the wrappers.

App.jsxApp.jsx
function ExpensiveList({ items, onSelect }) {
  const sorted = sortItems(items);
 
  return (
    <ul>
      {sorted.map((item) => (
        <li key={item.id} onClick={() => onSelect(item.id)}>
          {item.title}
        </li>
      ))}
    </ul>
  );
}

The compiler tracks the values that flow into each component and reuses the previous output when nothing relevant changed, which covers the memo, useMemo, and useCallback work from the first version. Compiled components show a sparkle (✨) badge in React DevTools so you can confirm it is running. The result is invisible to users but measurable in the Profiler, where the compiled component stops appearing in commits whose inputs did not change.

Compiler versus manual memo

TaskManual memoizationReact Compiler
Skip child re-rendersWrap the child in memoApplied automatically
Cache a valueWrap it in useMemoApplied automatically in components and hooks
Cache a functionWrap it in useCallbackApplied automatically in components and hooks
Code to maintainWrappers and dependency arraysPlain component code

Adopt it carefully

The compiler relies on your code following the Rules of React. When a component or hook breaks those rules, the compiler skips optimizing it and the companion ESLint plugin flags the file. Install eslint-plugin-react-hooks at its latest version, where the compiler rules live in the recommended-latest preset, and fix the reported violations over time.

You can also opt a single component out with the "use no memo" directive while you fix a problem, then remove the directive. The ESLint plugin reports each component the compiler would skip, so fixing a report directly increases the number of optimized components.

The compiler is meant to be adopted incrementally, which is why measuring before you change anything still applies. For existing code, keeping memo and useMemo and useCallback in place is fine, since removing them can change compiled output.

Rune AI

Rune AI

Key Insights

  • React Compiler memoizes components and hooks automatically at build time.
  • It is stable, optional, and enabled through your build tool.
  • Install babel-plugin-react-compiler and let it run first.
  • Compiled components show a sparkle badge in React DevTools.
  • You can keep manual memo calls or remove them after testing.
RunePowered by Rune AI

Frequently Asked Questions

Is React Compiler stable?

Yes. The current React documentation describes React Compiler as stable and tested in production. It is still optional, and you enable it through your build tool.

Do I need to remove my existing useMemo and useCallback calls?

No. The compiler can work alongside existing memoization. For new code, rely on the compiler. For existing code, leave the calls in place or test carefully before removing them.

Conclusion

React Compiler performs the memoization work that you would otherwise do by hand with memo, useMemo, and useCallback. Enable it through your build tool, follow the Rules of React so it can optimize safely, and reserve manual memoization for the few places where you need precise control.