React Compiler: memoization without useMemo
React Compiler memoizes components and values at build time, so most useMemo, useCallback and React.memo calls become unnecessary. What it does and how to adopt it.
React re-renders a component whenever its state or its parent changes. To avoid repeating expensive work, developers have wrapped values in useMemo, functions in useCallback and components in React.memo. It works, but it is manual, easy to get wrong and noisy to read. A missing dependency causes a bug. A forgotten wrapper causes a slow screen.
React Compiler does that job for you at build time.
What it changes
// Before: memoization by hand
const visible = useMemo(() => items.filter(matchesFilter), [items, matchesFilter]);
const onSelect = useCallback((id) => select(id), [select]);
// With the compiler: plain code, the same result
const visible = items.filter(matchesFilter);
const onSelect = (id) => select(id);
The compiler reads each component and hook, works out which values depend on which inputs, and inserts caching so that work is skipped when those inputs have not changed. It can memoize more precisely than most people do by hand, including values inside conditions.
It is a build tool, not a React 19 feature
The two are often mixed up because they were announced close together. React Compiler is a separate build step. Its first stable release, version 1.0, came in October 2025. It works with React 19 and also with React 17 and 18.
For what React 19 itself added, see React 19: Actions, the use API and Server Components.
How to adopt it
- Turn on the lint rules first. The compiler relies on the Rules of React: components must be pure, and props and state must not be mutated. The React hooks ESLint plugin reports code that breaks them.
- Install the plugin. The compiler ships as
babel-plugin-react-compiler. Next.js and Vite each document a short setup for it. - Start with part of the app. You can enable it for one folder, check the result, then widen it.
- Leave existing memoization alone at first. Old
useMemoanduseCallbackcalls keep working. Remove them gradually as you touch the files.
If a specific component misbehaves, the "use no memo" directive opts it out while you investigate.
What it does not fix
- Slow work that genuinely has to run. Memoization skips repeated work. It does not make the first run faster.
- Huge lists. Thousands of rows still need pagination or virtualization.
- Data fetching problems. Request waterfalls and oversized payloads are outside its reach.
- Code that breaks the rules. The compiler skips components it cannot safely optimize, so those stay as slow as they were.
Should you use it?
For a new React project, yes, from the first commit. For an existing codebase, enable the lint rules, fix what they report and roll the compiler out in stages. The result is less code to write, fewer re-render bugs and components that read like plain JavaScript again.