React

React Compiler in production: you can stop writing useMemo

What the compiler memoizes for you, the rules it relies on, how to roll it out one folder at a time, and what to do with the useMemo you already have.

ANAbhay Nikam, Founder, Navio Labs

Every React codebase we’ve inherited has the same argument buried in its code review history: should this be wrapped in useMemo? Should that callback use useCallback? Does this component need React.memo? The answers were usually guesses, and the guesses were usually wrong in one direction or the other.

React Compiler 1.0, released on October 7, 2025, ends most of that argument. It’s a build-time tool that adds memoization for you, based on an analysis of your code rather than a developer’s hunch. Here’s what it does, what it needs from you, and how we roll it out.

What it actually does

The compiler reads your components and hooks at build time and inserts memoization automatically — the equivalent of useMemo, useCallback and React.memo, but applied consistently and more precisely. It can even memoize after an early return, which you can’t do by hand because hooks can’t be called conditionally.

It works with React and React Native, and it’s currently a Babel plugin. The React team says it has been tested on major apps at Meta. For example, on the Meta Quest Store they report initial loads and cross-page navigations improving by up to 12%, and some interactions getting more than 2.5× faster, with memory use staying neutral. Your results will depend on how much unnecessary re-rendering your app was doing in the first place.

What it needs from you: the Rules of React

The compiler assumes your code follows the Rules of React: components and hooks are pure during render, props and state are treated as immutable, and hooks are called unconditionally at the top level. Code that breaks the rules — mutating props, reading refs during render, setting state during render — may be skipped or, worse, behave differently once memoized.

The good news is you don’t have to find violations by hand. The compiler’s checks ship as lint rules in eslint-plugin-react-hooks, and they work even if you haven’t installed the compiler yet:

// eslint.config.js
import reactHooks from 'eslint-plugin-react-hooks'
import { defineConfig } from 'eslint/config'

export default defineConfig([
  reactHooks.configs.flat.recommended,
])

If you previously installed eslint-plugin-react-compiler, remove it; its rules now live here. The new rules catch things like setting state during render (an infinite-loop risk), expensive work inside effects, and unsafe ref access during render.

Turn on the lint rules first, everywhere, before you enable the compiler anywhere. Fixing what they find is the real work of adopting the compiler.

Installing it

npm install --save-dev --save-exact babel-plugin-react-compiler@latest

Then enable it for your toolchain:

  • Next.js: new apps can pick the compiler in create-next-app. For existing apps, enable it in next.config and use Next.js 15.3.1 or later for better build performance.
  • Vite: add the compiler as a Babel plugin through the React plugin, or start from the compiler-enabled template.
  • Expo: SDK 54 and later enable it by default.

React version: React 19 needs nothing extra. React 17 and 18 are supported too — set a minimum target in the compiler config and add react-compiler-runtime as a dependency.

Note the --save-exact. The React team recommends pinning an exact version unless you have strong end-to-end tests, because a new compiler version can change memoization output. Upgrade it deliberately, like a framework, not as part of a routine dependency bump.

Rolling it out one folder at a time

On an existing app, we never switch the compiler on everywhere at once. The compiler supports gradual adoption, and we use it:

  1. Lint everywhere, compile nowhere. Merge the lint rules and fix violations. This alone usually turns up real bugs.
  2. Pick a low-risk directory. Settings pages, an admin area, a design-system folder. Configure the compiler to only compile those files.
  3. Ship it and watch. Check error tracking and run your end-to-end tests. Compare render counts or interaction timings in the React DevTools Profiler if performance is the goal.
  4. Widen the net. Add directories in small batches, leaving the scariest screens — checkout, editors, anything with complex effects — for last.
  5. Turn it on by default once most of the app is compiled, using the opt-out directive ("use no memo") for the rare component that can’t be fixed yet.

The "use no memo" directive is an escape hatch, not a long-term home. Track every use and fix them over time.

What to do with your existing useMemo and useCallback

This is the question everyone asks. The React team’s guidance, which matches our experience:

  • New code: don’t write useMemo or useCallback by default. Let the compiler handle it. Reach for them only when you need precise control.
  • Existing code: leave it alone, or remove it carefully with tests. Removing manual memoization can change the compiled output, and it’s not worth a risky cleanup PR just to delete lines.

The main case where manual memoization still earns its place is a value used as an effect dependency, where you need to guarantee it stays stable so an effect doesn’t fire repeatedly. Being explicit there documents intent, too.

Where people get surprised

  • Effects that depended on unstable values. If an effect “worked” only because a dependency changed every render, memoization can stop it from re-running. That was a bug before; the compiler just exposes it.
  • Mutation during render. Building an array and then pushing to a prop object, or caching things on a ref during render, breaks once results are reused.
  • Third-party hooks that break the rules. Lint can’t see inside node_modules. If something odd happens after enabling a folder, check which libraries that folder uses.

Is it worth it?

For most apps on React 19, yes. The compiler removes a whole category of performance work and code-review debate, and the lint rules alone make a codebase healthier. Budget your time for fixing rule violations, not for the compiler itself — that part is a config change.

Still on React 18? Do the React 19 upgrade first, or use the compiler’s React 17/18 support while you plan it. If you’d rather have someone roll this out with you, that’s what we do.

Sources

More blogs

Rather have someone do this with you?

That’s what we do. Tell us where you’re stuck and you’ll hear back from the founder within one business day.

Start a project with Navio Labs
Get help with this