The React Compiler Is Here: Should You Delete Your useMemo?
by Maven Team, Software Development
A while ago we wrote about performance optimisation in React — React.memo, useMemo, useCallback, and the discipline of stopping unnecessary re-renders by hand. That advice was correct for its time. It is now largely obsolete.
The React Compiler reached its first stable release (1.0) in October 2025. It is a build-time tool that automatically memoises your components and hooks — and, in the React team's own words, applies memoisation that is "as precise, or moreso, than what you may have written" by hand. So the question we now get from clients is a fair one: if the compiler handles memoisation, should we delete all our useMemo and useCallback calls?
Mostly yes. But "mostly" is doing real work in that sentence, and getting the exceptions right is what separates a clean adoption from a subtle regression.
What the React Compiler actually does
Every time a component renders, React re-runs its body: it recreates objects, arrays, and functions, and recomputes derived values. Most of that is cheap. The expensive part is when those fresh references cascade — a new function identity forces a memoised child to re-render, which forces its children to re-render, and so on.
For a decade the fix was manual: wrap the value in useMemo, wrap the callback in useCallback, wrap the child in React.memo, and hand-maintain a dependency array for each.
// The manual approach — correct, but noisy and easy to get wrong
const sorted = useMemo(() => sortRows(rows), [rows])
const onSelect = useCallback((id) => setSelected(id), [])
The React Compiler does this analysis at build time. It reads your component, works out exactly which values depend on which inputs, and inserts memoisation automatically — no directives, no dependency arrays, no useMemo in your source at all.
// With the compiler — you write the obvious thing, it handles memoisation
const sorted = sortRows(rows)
const onSelect = (id) => setSelected(id)
Because it derives dependencies from the actual code rather than a hand-written array, it also fixes a whole class of bugs: stale closures and missing dependencies that used to slip past code review.
So — delete your useMemo?
For the vast majority of call sites, yes. Once the compiler is enabled, hand-written useMemo and useCallback become escape hatches for precise control, not default tools — that is exactly how the React docs frame them now that the compiler does the work. Removing them makes components dramatically easier to read, and the compiler's memoisation is usually finer-grained than what you had.
But keep them — or leave them in place — in these cases:
- A value feeds a
useEffectdependency array and you rely on its reference identity. If an effect fires based on whether a value "changed," removing the manual memo can subtly alter reference stability and cause the effect to over-fire (or under-fire). These are the removals to review most carefully. - Library and design-system code. When you publish components other teams consume, you sometimes need an explicit memoisation guarantee at the boundary rather than trusting each consumer's build setup.
- Genuinely expensive work whose inputs change every render. This is the big one, and it is a misconception worth killing.
What the compiler does not fix
The React Compiler eliminates re-renders caused by unstable references. It does not speed up work whose inputs genuinely change on every render, and it does not rescue a bad architecture.
If you sort ten thousand rows and the array is a new value each render, the compiler cannot memoise that away — the input really did change. The React team is explicit about the boundary: the compiler only memoises "React components and hooks, not every function," and its memoisation is not shared across components. Genuinely expensive work is a data-flow and architecture problem: paginate, virtualise, move it to the server, lift it out of the render path — or, as the docs suggest, memoise that function outside React. The compiler removes the ceremony around performance; it does not remove the thinking.
This is the distinction we spend the most time on in a React codebase audit. Teams often expect the compiler to be a magic "make it fast" switch and are surprised when a genuinely heavy render is still heavy. Memoisation was never the whole story.
Adopting it safely
The good news for teams not yet on the latest React: you do not need React 19. The React team states the compiler is designed to work best with React 19 "but it also supports React 17 and 18" — so being on React 18 is not a blocker to adopting it.
A pragmatic rollout:
- Add the ESLint rule first. The compiler relies on your components following the Rules of React. As of 1.0 the compiler-powered lint rules ship inside
eslint-plugin-react-hooks, flagging the violations that would otherwise silently opt a component out of optimisation. Fixing these is valuable on its own. - Turn it on incrementally. In annotation mode you opt a component in with the
'use memo'directive and opt one out with'use no memo'— so you can roll it out file by file, and back a component out if it misbehaves, rather than converting the whole codebase in one commit. - In Next.js, enable it through the framework's React Compiler config flag and let the bundler apply the transform — no separate Babel wiring. (Next.js, Vite and Expo now ship the compiler in their new-app templates.)
- Review effect-heavy components last and carefully. As above, that is where removing manual memoisation can change behaviour rather than just tidy it.
- Then delete the noise. Once a component is compiled and green, its
useMemo/useCallbackscaffolding can usually come out — leaving code that reads like the problem it solves.
The takeaway
The React Compiler is one of the most significant quality-of-life changes in React's history: it moves an entire category of performance work from the developer to the build tool, and it does the job more reliably than we did by hand. Delete the memoisation that existed only to keep references stable — that was always compiler work we were doing manually.
Keep the small amount that encodes a genuine guarantee, and remember that the compiler makes your components stop re-rendering unnecessarily — it does not make genuinely expensive work cheap. That part is still design.
If your team is weighing an upgrade — whether you are on React 18 and wondering if it is worth it, or on 19 and unsure how aggressively to strip memoisation — we are happy to talk it through.
Sources — official React documentation: